使用 CMake 在 Windows(MSVC) 中查找库

Find libraries in Windows(MSVC) with CMake

本文关键字:查找 MSVC CMake Windows 使用      更新时间:2023-10-16

im 在尝试链接 MSVC 中的库时遇到问题。我有一些外部依赖项,我已经编译用于发布和调试,并将它们设置在不同的文件夹中(${PROJECT_SOURCE_DIR}/External/Debug/lib 和 ${PROJECT_SOURCE_DIR}/External/Release/lib)。我编写了一些 FindFoo.cmake 模块,这些模块作为find_library命令的提示 ${EXTERNAL_LIB_DIR},该命令根据 ${CMAKE_BUILD_TYPE} 设置。

这项工作在 Linux 上完善,但在 Windows 中失败(它总是将EXTERNAL_LIB_DIR路径设置为调试路径),并且由于_ITERATOR_DEBUG_LEVEL而无法链接。

这是我正在使用的FindFoo.cmake的示例。

FIND_PATH(SOIL_INCLUDE_DIR                                                                                    
NAMES SOIL/SOIL.h                                                                                         
PATHS                                                                                                     
${EXTERNAL_DIR}/soil/inc                                                                                  
NO_DEFAULT_PATH                                                                                           
)                                                                                                         

find_library(                                                                                                 
SOIL_LIBRARY                                                                                              
NAMES SOIL soil soil_debug                                                                            
PATHS                                                                                                     
${EXTERNAL_LIB_DIR}                                                                                   
NO_DEFAULT_PATH                                                                                       
)                                                                                                         

INCLUDE(FindPackageHandleStandardArgs)                                                                        
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SOIL DEFAULT_MSG SOIL_LIBRARY S 
SOIL_INCLUDE_DIR)                             

if (${SOIL_FOUND})                                                                                            
SET(SOIL_INCLUDE_DIRS ${SOIL_INCLUDE_DIR})                                                                
SET(SOIL_LIBRARIES    ${SOIL_LIBRARY})                                                                    
endif()                                                                                                       

MARK_AS_ADVANCED( SOIL_LIBRARY SOIL_INCLUDE_DIR ) 

在这里创造了EXTERNAL_LIB_DIR # 设置外部库

set(EXTERNAL_DIR ${PROJECT_SOURCE_DIR}/External)                                                              
if (${CMAKE_BUILD_TYPE} MATCHES Debug)                                                                        
set(EXTERNAL_LIB_DIR ${PROJECT_SOURCE_DIR}/External/lib/Debug)                                            
else()                                                                                                        
set(EXTERNAL_LIB_DIR ${PROJECT_SOURCE_DIR}/External/lib/Release)                                          
endif()                                                                                                       
message(STATUS "Using libraries in ${EXTERNAL_LIB_DIR}") 

我应该如何修改创建EXTERNAL_LIB_DIR变量的 FindFoo.cmake 以使其与 MSVC 一起使用?

谢谢

您将需要两个不同的find_library调用,一个用于调试,一个用于发布。

find_library(SOIL_LIBRARY_DEBUG NAMES soil_debug
PATHS ${PROJECT_SOURCE_DIR}/External/lib/Debug
NO_DEFAULT_PATH)
find_library(SOIL_LIBRARY_RELEASE NAMES SOIL soil 
PATHS ${PROJECT_SOURCE_DIR}/External/lib/Release
NO_DEFAULT_PATH)
set(SOIL_LIBRARIES debug ${SOIL_LIBRARY_DEBUG} optimized ${SOIL_LIBRARY_RELEASE})
target_link_libraries(foo ${SOIL_LIBRARIES})

请注意,这仍然不完全正确,因为它不能正确区分所有四种默认配置(调试,发布,MinSizeRel和RelWithDebInfo),但对于大多数用例来说已经足够了。

在现代 CMake 中,查找脚本通常创建导入的目标,而不是通过变量公开查找结果,如果需要,理论上可以提供与配置文件包相同的灵活性。看看较新的CMake版本附带的脚本,以了解它的外观(FindZlib.cmake是一个很好的例子,因为它相当小)。

永远不要在查找脚本中依赖CMAKE_BUILD_TYPE,因为它仅受单一配置生成器(如 Makefiles)支持!

我想详细说明ComicSansMS的答案。他为我指出了正确的方向。

我来这里是因为我正在寻找一种解决方案来查找Linux和MS Windows上的GoogleTest安装库。首先,我看了一下cmake模块 FindGTest,但这有点问题(不提供正确的目录),也没有提供我也需要的gmock路径。所以我决定自己使用 cmakefind_library()查找目录。

安装谷歌测试在这里不是问题。我在build/目录上使用其默认安装并得到:

# On Linux with build type Debug
tree build/lib/
build/lib/
├── libgmock_maind.a
├── libgmockd.a
├── libgtest_maind.a
└── libgtestd.a
# On Linux with build type Release
tree build/lib/
build/lib/
├── libgmock.a
├── libgmock_main.a
├── libgtest.a
└── libgtest_main.a

请注意,库名称后附加了一个带有Debugd。较新的安装将覆盖旧安装。

# On MS Windows with build type Debug and Release
build/lib/
├── Debug
│   ├── gmock_maind.lib
│   ├── gmock_maind.pdb
│   ├── gmockd.lib
│   ├── gmockd.pdb
│   ├── gtest_maind.lib
│   ├── gtest_maind.pdb
│   ├── gtestd.lib
│   └── gtestd.pdb
└── Release
├── gmock.lib
├── gmock_main.lib
├── gtest.lib
└── gtest_main.lib

MS Windows不会覆盖旧的构建类型,但它具有其他子目录。例如,我希望所有四个库gtest[d]gtest_main[d]gmock[d]gmock_main[d]都添加为两个操作系统上链接目标的库,而无需修改:

message("CMAKE_FIND_LIBRARY_PREFIXES is: ${CMAKE_FIND_LIBRARY_PREFIXES}")
message("CMAKE_FIND_LIBRARY_SUFFIXES is: ${CMAKE_FIND_LIBRARY_SUFFIXES}")
find_library(GTEST_STATIC_LIBRARY gtest gtestd
PATHS ${CMAKE_BINARY_DIR}/lib
PATH_SUFFIXES Debug Release MinSizeRel RelWithDebInfo
NO_DEFAULT_PATH)
message("GTEST_STATIC_LIBRARY is: ${GTEST_STATIC_LIBRARY}")
find_library(GMOCK_STATIC_LIBRARY gmock gmockd
PATHS ${CMAKE_BINARY_DIR}/lib
PATH_SUFFIXES Debug Release MinSizeRel RelWithDebInfo
NO_DEFAULT_PATH)
message("GMOCK_STATIC_LIBRARY is: ${GMOCK_STATIC_LIBRARY}")
find_library(GTEST_MAIN_STATIC_LIBRARY gtest_main gtest_maind
PATHS ${CMAKE_BINARY_DIR}/lib
PATH_SUFFIXES Debug Release MinSizeRel RelWithDebInfo
NO_DEFAULT_PATH)
message("GTEST_MAIN_STATIC_LIBRARY is: ${GTEST_MAIN_STATIC_LIBRARY}")
find_library(GMOCK_MAIN_STATIC_LIBRARY gmock_main gmock_maind
PATHS ${CMAKE_BINARY_DIR}/lib
PATH_SUFFIXES Debug Release MinSizeRel RelWithDebInfo
NO_DEFAULT_PATH)
message("GMOCK_MAIN_STATIC_LIBRARY is: ${GMOCK_MAIN_STATIC_LIBRARY}")
link_libraries(${GTEST_STATIC_LIBRARY} ${GMOCK_STATIC_LIBRARY}
${GTEST_MAIN_STATIC_LIBRARY} ${GMOCK_MAIN_STATIC_LIBRARY})

如果两个版本都可用,则此顺序将仅与发布版本匹配。如果您希望先匹配调试,则只需对库名称重新排序即可。有了PATH_SUFFIXES,查找将匹配所有可能的构建类型。结果我得到发布:

# On Linux:
~$ rm -rf build/ && cmake -S . -B build -D CMAKE_BUILD_TYPE=Release
--- snip ---
CMAKE_FIND_LIBRARY_PREFIXES is: lib
CMAKE_FIND_LIBRARY_SUFFIXES is: .so;.a
GTEST_STATIC_LIBRARY is: /home/ingo/develbuild/lib/libgtest.a
GMOCK_STATIC_LIBRARY is: /home/ingo/develbuild/lib/libgtest.a
GTEST_MAIN_STATIC_LIBRARY is: /home/ingo/develbuild/lib/libgtest_main.a
GMOCK_MAIN_STATIC_LIBRARY is: /home/ingo/develbuild/lib/libgmock_main.a
rem On MS Windows:
~>cmake --build build --config Release
--- snip ---
CMAKE_FIND_LIBRARY_PREFIXES is:
CMAKE_FIND_LIBRARY_SUFFIXES is: .lib
GTEST_STATIC_LIBRARY is: C:/Users/ingo/devel/build/lib/Release/gtest.lib
GMOCK_STATIC_LIBRARY is: C:/Users/ingo/devel/build/lib/Release/gmock.lib
GTEST_MAIN_STATIC_LIBRARY is: C:/Users/ingo/devel/build/lib/Release/gtest_main.lib
GMOCK_MAIN_STATIC_LIBRARY is: C:/Users/ingo/devel/build/lib/Release/gmock_main.lib

CMAKE_FIND_LIBRARY_PREFIXES和MAKE_FIND_LIBRARY_SUFFIXES由cmake正常初始化。