add_library,target_link_libraries,set_target_properties,target_link_libraries使用联系

本文介绍如何使用CMake在Linux环境下构建一个名为libsugan的静态库,并链接OpenCV等依赖库。文章详细展示了CMakeLists.txt配置文件的具体写法,包括设置编译选项、查找外部库、指定源文件及最终生成静态库的过程。

折腾了半下午,终于知道这个货是怎么个关系了。在此写下记录,希望遇到同样问题的同学,不要再次浪费时间了。

首先我是在Linux环境下

先列出我的CmakeLists.txt

注意,在CmakeLists.txt 里,注释用的是#


project(Camera_sugan)         #工程名字
cmake_minimum_required(VERSION 2.6)    #编译最低cmake版本
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )   #设置c++编译器

find_package(OpenCV REQUIRED)    #在整个电脑上找opencv包

include_directories(                                 #包含头文件路径
    ./include/inudev/
    ./src/
)

set(SRC_LISTS                                          #将所有的源文件列为一个集合,集合名字叫做SRC_LISTS
    ./src/inuitive.cpp
    ./src/runCamera_Qfeeltech.cpp
)

add_library(libsugan ${SRC_LISTS})    #将集合里的所有的源文件生成一个静态库,该静态库的名字libsugan,注意,在整个CmakeLists里都要用libsugan这个

                                                                        #名字来代替之前那个集合生成的库。
target_link_libraries(libsugan                  #链接静态库需要的依赖库
    ${OpenCV_LIBS}
    ${PROJECT_SOURCE_DIR}/lib/libCommonUtilities.so
    ${PROJECT_SOURCE_DIR}/lib/libInuStreams.so
)
#到此为止就在程序中生成了一个名字为libsugan的静态库,但是我们知道Linux下对库的存储格式是lib+name.a,所以我们生成的静态库名字为libsugan,那么

#存储出来的结果就是liblibsugan.a,看着很别扭,为了大众点,我们用下面这句,保证了存储出来的静态库叫做libsugan.a,

#但是请千万注意,在整个CmakeLists.txt里

#如果想链接生成的这个库必须使用    “add_library(libsugan ${SRC_LISTS})”指明的名字。
set_target_properties(libsugan PROPERTIES OUTPUT_NAME "sugan")

add_executable(demo ./src/main.cpp)
target_link_libraries(demo libsugan)




<think> 我们正在讨论CMake中的链接操作。用户之前询问了`target_link_libraries`的作用,现在他们想知道如果不使用`target_link_libraries`而直接使用库会有什么后果。 根据引用[1],我们了解到`target_link_libraries`是用于指定目标链接的库,而其他命令如`link_directories`和`link_libraries`是全局设置,但现代CMake推荐使用`target_link_libraries`。 如果不使用`target_link_libraries`,可能采取的方式包括: 1. 使用全局链接命令(如`link_libraries`)来添加库。 2. 手动在链接命令中指定库(比如通过直接设置`CMAKE_EXE_LINKER_FLAGS`)。 3. 完全不指定链接库,试图通过包含头文件来使用库(这显然在链接阶段会失败)。 后果包括: - **链接错误**:最常见的是`undefined reference`错误,因为链接器不知道在哪里找到库的实现。 - **依赖传递性问题**:在具有复杂依赖关系的项目中,全局链接设置可能导致依赖传递混乱,例如库的链接顺序错误,或者不必要的库被链接进来。 - **可维护性差**:全局设置(如`link_libraries`)会影响所有目标,可能导致目标之间相互干扰,难以管理。 - **跨平台问题**:不同平台库的命名和链接方式不同,手动管理容易出错。 具体分析如下: 1. **未解决符号引用(Undefined Reference)**: 使用库不仅需要头文件(编译时),还需要在链接时提供库的二进制文件。如果不使用`target_link_libraries`,则链接步骤不会自动添加所需的库,导致链接器找不到函数或变量的定义。 例如,假设我们有一个库`mylib`,其中定义了一个函数`void foo();`,我们在代码中调用了`foo()`。在编译时,包含头文件可以通过,但链接时如果没有将`mylib`链接到可执行文件,则会出现: ``` undefined reference to `foo()' ``` 2. **库的搜索路径问题**: 即使你手动指定了库的名字,如果没有使用`target_link_libraries`(或`link_directories`设置搜索路径),链接器可能找不到库文件。`target_link_libraries`会自动处理库的搜索路径(特别是当库是通过`find_package`或`find_library`找到时)。 3. **链接顺序问题**: 链接器处理库的顺序很重要。如果库A依赖于库B,那么A必须出现在B之前(或者使用支持依赖解析的链接器选项,如`--start-group`)。`target_link_libraries`会按照依赖关系自动调整链接顺序,而手动指定则可能出错。 4. **构建配置区分(Debug/Release)**: 现代CMake允许为不同构建类型链接不同库(如Debug版本链接带调试信息的库)。如果不使用`target_link_libraries`的相应特性(如`debug`和`optimized`关键字),则无法方便地实现这一点。 5. **目标属性污染**: 使用全局命令(如`link_libraries`)会将库添加到所有后续目标中,即使某些目标并不需要这些库。这会导致: - 可执行文件或库链接了不必要的库,增大二进制文件体积。 - 可能引入意外的符号冲突。 6. **依赖传递性控制缺失**: `target_link_libraries`的`PUBLIC`、`PRIVATE`和`INTERFACE`关键字可以精确控制依赖关系如何传递。如果不用它,就无法实现这种控制,可能导致: - 库的内部依赖泄露给使用者(违反封装)。 - 需要使用者手动链接传递依赖,增加使用复杂度。 举例说明: 假设我们有一个静态库`inner`,它使用了数学库`m`(在Linux上是`libm.so`)。我们还有一个共享库`outer`,它使用了`inner`。如果使用`target_link_libraries`,我们可以这样写: ```cmake add_library(inner STATIC inner.c) # inner需要链接数学库,但这是其内部实现,不应该暴露给使用target_link_libraries(inner PRIVATE m) # m是数学库 add_library(outer SHARED outer.c) # outer只需要链接inner,而inner的私有依赖m不会传递给outer target_link_libraries(outer PUBLIC inner) ``` 这样,当另一个可执行文件链接`outer`时,它只需要链接`outer`和`inner`,而不需要知道`inner`还依赖`m`,因为`inner`的`PRIVATE`依赖不会传递。 但是,如果不使用`target_link_libraries`,而是使用全局链接命令: ```cmake link_libraries(m) # 全局添加数学库 add_library(inner STATIC inner.c) # 会自动链接m add_library(outer SHARED outer.c) target_link_libraries(outer inner) # 这里outer也会链接m,因为全局设置 ``` 这样,`outer`也链接了`m`,但实际上它可能并不需要。而且,如果`outer`被其他目标使用,那么`m`也会被传递给其他目标,造成污染。 或者,如果手动设置链接标志: ```cmake set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lm") ``` 这样所有可执行文件都会链接数学库,同样会造成污染。 结论:不使用`target_link_libraries`而直接使用库,会导致链接错误、依赖管理混乱、目标之间耦合度增加、可维护性降低等问题。因此,在现代CMake实践中,强烈推荐使用`target_link_libraries`来管理链接依赖。 现在,我们按照要求生成相关问题。 </think>### 不使用 `target_link_libraries` 直接链接库的后果分析 在 CMake 项目中若跳过 `target_link_libraries` 直接使用库,会导致以下关键问题: #### 1. **符号解析失败(链接错误)** 当直接调用库函数而未正确链接时,链接器无法解析函数符号,产生 `undefined reference` 错误: ```bash main.cpp:(.text+0x15): undefined reference to `log_function()' [^1] ``` **根本原因**: 头文件仅提供声明,`target_link_libraries` 负责将二进制实现(.so/.a)与目标绑定。直接包含头文件无法解决符号引用问题。 #### 2. **依赖传递性失控** 在模块化项目中,缺失作用域控制会导致: - **依赖泄露**:内部库被意外暴露给使用者 - **依赖缺失**:必要传递库未自动链接 ```cmake # 错误示例:直接全局链接 link_libraries(math_lib) # 污染所有目标 [^1] ``` #### 3. **构建配置混乱** 无法区分不同构建配置的库版本: ```cmake # 正确方式:区分Debug/Release target_link_libraries(app debug math_d.lib optimized math.lib ) ``` 直接链接将导致: - 调试版本错误链接发布版库 - 发布版本携带调试符号增大体积 #### 4. **跨平台兼容性问题** 特殊平台(如 Android NDK)需处理: - ABI 差异(armeabi-v7a/arm64-v8a) - 系统库路径规则 手动管理将导致: ```bash ld: cannot find -lffmpeg # 因路径错误导致的链接失败 ``` #### 5. **目标属性污染** 全局指令如 `link_directories()` 影响所有目标,可能引发: - 库版本冲突(例如 OpenCV3 vs OpenCV4) - 意外链接错误版本的库 ```cmake link_directories(/wrong/path) # 污染全局路径 [^1] ``` ### 正确与错误实践对比 | 场景 | 正确方式 | 直接链接的后果 | |---------------------|----------------------------------|----------------------------| | 链接第三方库 | `target_link_libraries(app PRIVATE ffmpeg)` | 符号未定义错误 | | 多配置构建 | 使用 `debug`/`optimized` 限定符 | 版本错配,性能/稳定性问题 | | 传递依赖 | `PUBLIC`/`PRIVATE` 控制传播 | 依赖泄露或缺失 | | Android ABI 适配 | `set_target_properties` + 链接 | ABI 不兼容崩溃 | > **本质区别**:`target_link_libraries` 是 **声明式依赖管理**,直接链接是 **命令式硬编码**。前者确保: > $$ \text{可执行文件} \oplus \text{依赖库} \xrightarrow{\text{链接器}} \text{完整二进制实体} $$ > 后者丢失了 CMake 的依赖关系建模能力[^1]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值