代码:https://gitee.com/Kyle12/StudyProject/tree/master/cmake/lib_debug_release
CMake Debug后缀
set_target_properties(liba PROPERTIES DEBUG_POSTFIX "d") 或者 set(CMAKE_DEBUG_POSTFIX "d") 这样生成的库或者exe程序名会多一个d字符。如下
链接 vc++ 运行时库
通过/MD、/MT 可以改变MSVC运行库,
- /MD代表使用动态运行时库,程序运行时需要有MSVCRversionnumber.DLL,这些库是通过安装Download Microsoft Visual C++ Redistributables 获得。例如msvcp140.dll就是在 Microsoft Visual C++ Redistributable for Visual Studio 2015中。
- /MT会使用静态运行时库,MSVC库会编译链接到exe程序中,所以系统不安装VC++库也可以正常运行,但是这会增加exe的大小,且由于不能共享使用公用的DLL也会消耗更多内存。
- /MD、/MT都有对应的debug版,/MDd、/MTd,链接时使用的库也是对应的Debug版,例如msvcp140d.dll则是VC++ 2015的Debug版库。这种库需要安装Visual studio 20xx时才能获得,非开发设备一般都没有这种库。
Debug库和Release库
MSVC中需要区分Debug库和Release库,因为Debug和Release模式下STL的实现不一样。例如 x64架构下std::vector和std::string的sizeof大小,Debug模式下为32和40,而Release模式下为24和32。之所以不一样是因为Debug模式下会存储额外的调试信息。
因为C++ STL对象Debug库和Release模式下大小不一致,所以链接库的时候需要注意库是Debug版还是Release版本,需要根据当前程序是Debug还是Release版本选择对应的库版本。
MSVC 链接动态库
对于动态库都有对应的DLL,DLL本身就是可以执行文件,系统可以直接读取并执行,其内部已经包含了所有运行时的函数和符号。所以动态库生成后其已经可以与编译环境分离,也就是说如果你编译了一个动态库,这个库也不会受编译器版本的限制,大部分情况下不同VS版本都可以通用。
如果动态库的API没使用C++ STL对象,或者所有的API使用C语言接口,此时在使用库时可以不用区分Debug版本还是Releas版本,Debug版可以直接使用Release版本的库。这也是为什么很多库使用C++编写,却提供C语言的接口。
如果使用了使用C++ STL对象,需要严格按照Debug版使用Debug版本的库,Release版本使用Release版本的库,否则程序可以链接成功,但是运行时会报内存错误,而且这个错误很难被察觉。
MSVC 链接静态库
静态库只是一个中间编译状态,并不能直接运行,还需要与调用者编译链接才能运行。使用库时需要严格按照Debug版链接Debug版本的库,Release版本链接Release版本的库。因为是中间状态所以在VS2015之前,不同版本VS编译的静态库都不能通用,必须要相同版本才能编译链接。VS2015以后微软队各个版本的静态库abi做了兼容,所以VS2015后大部分静态库可以通用。
如果Debug版C++程序链接Release版静态库时,链接会报错,以下是VS2022的报错:
liba.lib(a.cpp.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2”(main.cpp.obj 中)
liba.lib(a.cpp.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MD_DynamicRelease”不匹配值“MDd_DynamicDebug”(main.cpp.obj 中)
LINK : warning LNK4098: 默认库“MSVCRT”与其他库的使用冲突;请使用 /NODEFAULTLIB:library
E:\Study\StudyProject\cmake\lib_debug_release\main.exe : fatal error LNK1319: 检测到 2 个不匹配项
这是因为Debug版和Release版默认使用的vc++ 运行时库不相同,默认情况下Debug版使用/MDd,Release版使用/MD,两者不相同导致报错。
所以在链接库时需要区分Debug版和Release版。在CMake可以如下设置:
target_link_libraries(target $<$<CONFIG:Release>:liba.lib> $<$<CONFIG:Debug>:libad.lib>)
C语言静态库
上面说的都是关于C++的,实际上如果一个库是使用C开发的,那么这个库不会受VC++运行库的影响,也就是说你可以在Debug程序中链接一个C开发的Release的静态库。
很多开源库都是使用C开发的,所以在编译这些库的静态库时,只需要编译一个Release版。
参考