CMake如何正确引入外部链接库的头文件?
我有一个用CMake构建的C++项目,想要引入外部sdsl库,当前使用的代码如下:
add_executable(my_app ${SOURCES}) find_library(SDSL sdsl) target_link_libraries(my_app PUBLIC ${SDSL})
静态库存储在/lib/libsdsl.a(CMake默认搜索路径),因此链接环节没有报错,但引入库的头文件时会出现file not found错误。手动添加target_include_directories(my_app PRIVATE "/include")可以解决问题,因为库的头文件默认安装在此路径。
但项目可能需要在其他环境编译,我想知道引入头文件的最佳方式:有没有类似find_library自动查找/lib/lib<libname>.a的方法,让CMake自动定位/include/<libname>/路径?
虽然可以通过设置CMAKE_PREFIX_PATH并添加target_include_directories(my_app PRIVATE "${CMAKE_PREFIX_PATH}/include")处理,但感觉这不是最佳实践。
作为CMake新手,我看到一个使用同款库的项目编译时也出现相同错误,该项目是多次分叉的版本,不同版本引入sdsl库的方式不同,我感到困惑。
针对sdsl库的CMake引入,不要单独使用find_library,正确的做法是用find_package——因为正规安装的sdsl-lite会提供CMake配置文件,能让CMake自动获取库的链接信息、头文件路径等所有依赖项。
1. 确保sdsl库正确安装
如果是从源码编译sdsl-lite,编译完成后必须执行安装步骤,这样CMake配置文件才会被放到系统默认搜索路径:
mkdir build && cd build cmake .. make sudo make install
2. 修改项目的CMakeLists.txt
替换原来的find_library相关代码,改成:
add_executable(my_app ${SOURCES}) # 查找sdsl库,REQUIRED参数表示找不到库就终止编译并报错 find_package(sdsl REQUIRED) # 直接链接sdsl提供的目标,CMake会自动处理头文件路径、库路径 target_link_libraries(my_app PUBLIC sdsl::sdsl)
这样修改后,CMake会自动读取sdsl的配置文件,不需要手动添加target_include_directories,跨环境编译时也能自动适配不同的安装路径。
3. 处理自定义路径安装的sdsl
如果sdsl没有安装到系统默认路径(比如安装在~/local/sdsl),只需要在运行CMake时指定CMAKE_PREFIX_PATH即可:
cmake -DCMAKE_PREFIX_PATH=~/local/sdsl ..
find_package会自动在指定路径下搜索sdsl的配置文件,同样能自动获取所有依赖信息。
为什么不推荐用find_library
find_library只能定位库文件本身,无法处理头文件路径、依赖库等关联信息,是一种非常基础的查找方式。而find_package是CMake官方推荐的第三方库引入标准,能完整获取库的构建元信息,是跨环境编译的最优解。
内容的提问来源于stack exchange,提问作者Ephesiel

