使用Mingw-w64编译FreeImage

时间:2022-09-06 07:38:32

最近在研究OpenGL的纹理,因此想寻找一款比较好的图片的加载库,用过轻量SOIL库,但是出现了Y轴颠倒的问题,还有部分图片无法读取。后来发现了FreeImage库,也能实现图片加载,并且能满足跨平台的需求。然而配置FreeImage编译,却不是那么的一帆风顺。
项目最开始考虑的就是要跨平台,其次就是不同的系统下不需要做更多的配置,每次拉一下代码就可以用,C++方面的选择一个是Cdt另一个便是Clion,综合比较选择了Clion,因为Clion基于Cmake,在跨平台上的优势绝对是杠杠的。
然而在Windows上的Clion是使用的MinGW编译器,不是使用的msvc,所以编译FreeImage会有很多的问题。这里按照流程说一下FreeImage的配置过程,当然首先你的电脑上需要安装MinGW-w64(MinGW-w32应该也可以,我没有做过测试),Cmake。然后去FreeImage的github页面,clone源码,前提是你安装了git,或者直接下载zip包源码。
打开cmd定位到FreeImage源码目录,因为FreeImage还依赖zlib和xmake项目,两个项目是以子模块的形式组织的,因此还需要更新这个两个项目。在命令行中输入如下命令即可

git submodule init
git submodule update

接着导出MinGW的MakeFile,最好在FreeImage下新建目录

md build
cd build
cmake -G "MinGW Makefiles" ..

这样在我们的build目录下就会生成MakeFile文件以及其他的cmake缓存文件,接下来就可以编译了,要在windows下面调用MinGW编译,需要先把MinGW安装目录下的bin目录加入到环境变量中。然后输入mingw32-make便可以进行编译,然而编译出现了如下错误

[ 29%] Building CXX object FreeImage/CMakeFiles/freeimage.dir/FreeImage/
BitmapAccess.cpp.obj
G__~1.EXE: error: /W0: No such file or directory
FreeImage\CMakeFiles\freeimage.dir\build.make:62: recipe for target
'FreeImage/CMakeFiles/freeimage.dir/FreeImage/BitmapAccess.cpp.obj' failed
mingw32-make[2]: *** [FreeImage/CMakeFiles/freeimage.dir/FreeImage/
BitmapAccess.cpp.obj] Error 1
CMakeFiles\Makefile2:152: recipe for target 'FreeImage/CMakeFiles/
freeimage.dir/all' failed
mingw32-make[1]: *** [FreeImage/CMakeFiles/freeimage.dir/all] Error 2
makefile:82: recipe for target 'all' failed
mingw32-make: *** [all] Error 2

从编译错误日志看,是编译的参数有/W0是无法被读取的。
查看FreeImage下的CmakeLists.txt,发现第169行,加入了/W0,然而却不被编译器识别,这里我们用#注释掉这一行,另外子目录下的包括LibMNG、LibOpenJPEG、LibPNG、LibRawLite、LibTIFF、OpenEXR下面的CmakeLists都要注释掉。然后再次编译,会遇到下面的错误

E:\workspace\FreeImage\FreeImage\PluginTIFF.cpp:199:23: error: cast from 
'thandle_t {aka void*}' to 'long int' loses precision [-fpermissive]
tif->tif_fd = (long)handle;
^

这是一个精度转换的问题,将PluginTIFF.cpp第199行代码改为

tif->tif_fd = *((int*)handle);

这样就可以编译通过了,编译完成会在build下面的lib目录中生成茫茫多的静态库。接下来便是使用了,这里我直接在FreeImage的父文件夹下创建一个CmakeLists.txt和一个main.cpp文件测试。
CmakeLists.txt

cmake_minimum_required(VERSION 2.8.12)
PROJECT(TestFreeImage)
include_directories(FreeImage)
add_subdirectory(FreeImage)
set(EXTRA_LIBS ${EXTRA_LIBS} freeimage jpeg mng rawlite tiff openexr openjpeg png zlib)
add_executable(TestFreeImage main.cpp)
target_link_libraries(TestFreeImage ${EXTRA_LIBS})

main.cpp

#include "FreeImage.h"
#include<stdio.h>
int main() {
FreeImage_Initialise(0);
int imgWidth, imgHeight, channel;
const char* imgFile = "test.png";
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
fif = FreeImage_GetFileType(imgFile);
if(fif == FIF_UNKNOWN) {
fif = FreeImage_GetFIFFromFilename(imgFile);
}
FIBITMAP* bitmap;
bitmap = FreeImage_Load(fif, imgFile);
imgWidth = FreeImage_GetWidth(bitmap);
imgHeight = FreeImage_GetHeight(bitmap);
unsigned char* imgBytes = FreeImage_GetBits(bitmap);
if(imgBytes) {
printf("img load success");
} else {
printf("img load error");
}
return 0;
}

仍然按照之前的方法在目录下创建test文件夹,在test文件夹下导出MinGW Makefiles

md test
cd test
cmake -G "MinGW Makefiles" ..

然后输入mingw32-make编译,这时会报错

[100%] Linking CXX executable TestFreeImage.exe
CMakeFiles\TestFreeImage.dir/objects.a(main.cpp.obj):main.cpp:(.text.startup+0xe
): undefined reference to `__imp_FreeImage_Initialise'
CMakeFiles\TestFreeImage.dir/objects.a(main.cpp.obj):main.cpp:(.text.startup+0x1
d): undefined reference to `__imp_FreeImage_GetFileType'
CMakeFiles\TestFreeImage.dir/objects.a(main.cpp.obj):main.cpp:(.text.startup+0x3
4): undefined reference to `__imp_FreeImage_Load'
CMakeFiles\TestFreeImage.dir/objects.a(main.cpp.obj):main.cpp:(.text.startup+0x4
0): undefined reference to `__imp_FreeImage_GetWidth'
CMakeFiles\TestFreeImage.dir/objects.a(main.cpp.obj):main.cpp:(.text.startup+0x4
9): undefined reference to `__imp_FreeImage_GetHeight'
CMakeFiles\TestFreeImage.dir/objects.a(main.cpp.obj):main.cpp:(.text.startup+0x5
e): undefined reference to `__imp_FreeImage_GetFIFFromFilename'
collect2.exe: error: ld returned 1 exit status
CMakeFiles\TestFreeImage.dir\build.make:105: recipe for target 'TestFreeImage.ex
e' failed
mingw32-make[2]: *** [TestFreeImage.exe] Error 1
CMakeFiles\Makefile2:74: recipe for target 'CMakeFiles/TestFreeImage.dir/all' fa
iled
mingw32-make[1]: *** [CMakeFiles/TestFreeImage.dir/all] Error 2
makefile:82: recipe for target 'all' failed
mingw32-make: *** [all] Error 2

查阅各种资料,发现__imp_XXX这种命名是动态链接,然而我们生成的是静态库,但是为什么main.cpp会认为自己是动态链接的呢?那么极有可能是函数声明的时候做了这样的事情,查看FreeImage.h会发现一些端倪。FreeImage第69-73行有如下代码

#ifdef FREEIMAGE_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif // FREEIMAGE_EXPORTS

这样在windows平台所有加了DLL_API的函数都会导出为动态链接,因此需要做一些修改,这里使用__MinGW__宏去判断,如果是使用MinGW编译器,重定义DLL_API,将这部分代码修改为

#if defined(__MINGW32__)
#define DLL_API
#else
#ifdef FREEIMAGE_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif // FREEIMAGE_EXPORTS
#endif

再次编译,仍出现以下报错

FreeImage/lib/librawlite.a(libraw_cxx.cpp.obj):libraw_cxx.cpp:(.text+0x23e7): un
defined reference to `__imp_htons'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x176b)
: undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x2ff4)
: undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x373b)
: undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x39a4)
: undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x3b95)
: undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x3d93)
: more undefined references to `__imp_ntohs' follow
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x10ebc
): undefined reference to `__imp_htonl'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x11094
): undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x1c346
): undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x1ca58
): undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x1d3c2
): undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x1e9ef
): undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x2f284
): undefined reference to `__imp_htonl'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x303cc
): undefined reference to `__imp_htonl'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x304ad
): undefined reference to `__imp_ntohl'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x3109a
): undefined reference to `__imp_htons'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x3159a
): undefined reference to `__imp_htons'
FreeImage/lib/librawlite.a(dcraw_common.cpp.obj):dcraw_common.cpp:(.text+0x31641
): undefined reference to `__imp_ntohl'
FreeImage/lib/librawlite.a(dcraw_fileio.cpp.obj):dcraw_fileio.cpp:(.text+0x5b8):
undefined reference to `__imp_ntohs'
FreeImage/lib/librawlite.a(dcraw_fileio.cpp.obj):dcraw_fileio.cpp:(.text+0x613):
undefined reference to `__imp_ntohs'
collect2.exe: error: ld returned 1 exit status
CMakeFiles\TestFreeImage.dir\build.make:105: recipe for target 'TestFreeImage.ex
e' failed
mingw32-make[2]: *** [TestFreeImage.exe] Error 1
CMakeFiles\Makefile2:74: recipe for target 'CMakeFiles/TestFreeImage.dir/all' fa
iled
mingw32-make[1]: *** [CMakeFiles/TestFreeImage.dir/all] Error 2
makefile:82: recipe for target 'all' failed
mingw32-make: *** [all] Error 2

这里报错是因为使用了winsock,在CMakeLists.txt加入ws2_32即可。

set(EXTRA_LIBS ${EXTRA_LIBS} freeimage jpeg mng rawlite tiff openexr openjpeg png zlib ws2_32)

这次再编译便可以编译通过,在test目录下生成了TestFreeImage.exe,这时候在命令行输入TestFreeImage,控制台显示img load error,放一张图片在test目录下,运行程序,控制台打印img load success,这样我们的FreeImage库就算是完美了。