答案是应避免使用link_directories,改用target_link_libraries直接传库文件全路径、find_library配合no_default_path查找,或通过add_library imported定义库目标并组合target_include_directories使用。

当你在CMakeLists.txt里写完add_executable却遇到undefined reference to 'xxx',第一反应可能是加link_directories——但这个命令在现代CMake中已不推荐使用,它容易掩盖路径依赖问题,且作用范围不可控。
为什么link_directories不推荐了
link_directories全局生效,所有后续target_link_libraries都会无差别尝试在这些路径里找库,哪怕目标根本不需要。更麻烦的是:它不传递、不记录、不校验路径是否存在,CMake生成构建系统时才真正检查——报错晚、定位难、调试成本高。
如果你的项目有多个可执行文件或库,其中一个依赖/opt/mylib,另一个依赖./third_party/openssl/lib,用link_directories把两个路径都加进去,不仅污染全局搜索空间,还可能引发同名库冲突(比如两个libcrypto.so版本不同)。
现代替代方案:优先用target_link_libraries直接传绝对路径
方法一:直接指定库文件全路径(最明确、最安全)
把libmyutils.a放在${CMAKE_SOURCE_DIR}/libs下,就写:
target_link_libraries(myapp ${CMAKE_SOURCE_DIR}/libs/libmyutils.a)
这一步操作起来很简单,直接把文件拖进去就行。CMake会自动识别静态库或动态库类型,无需额外声明。
方法二:配合find_library按需查找(适合系统库或标准安装路径)
find_library(MYLIB_LIB myutils HINTS ${CMAKE_SOURCE_DIR}/libs NO_DEFAULT_PATH)
if(NOT MYLIB_LIB)
message(FATAL_ERROR "myutils library not found in ${CMAKE_SOURCE_DIR}/libs")
endif()
CMake 4.3.2 Windows x86_64 历史版本安装包,适合旧项目兼容、构建环境回退、CMakeLists.txt 迁移验证、Visual Studio/Ninja/Makefile 生成器测试和 C/C++ 项目维护。
target_link_libraries(myapp ${MYLIB_LIB})
【注意】NO_DEFAULT_PATH必须显式加上,否则find_library会先去/usr/lib、/usr/local/lib等系统路径里翻找,可能误匹配到旧版本或不兼容的库。
真正推荐的工程级写法:target_include_directories + target_link_libraries组合
第一步:定义库目标(哪怕只是导入已有库)
add_library(myutils IMPORTED STATIC)
set_property(TARGET myutils PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/libmyutils.a)
第二步:声明该库的头文件路径和链接属性
target_include_directories(myutils INTERFACE ${CMAKE_SOURCE_DIR}/include)
set_target_properties(myutils PROPERTIES INTERFACE_COMPILE_OPTIONS "-fPIC")
第三步:让可执行目标依赖它
target_link_libraries(myapp PRIVATE myutils)
这样做的好处是:路径绑定到具体目标,不会泄漏;头文件路径随库自动注入;链接时自动处理依赖传递;未来迁移到find_package或pkg_check_modules也无缝衔接。










