cmake:EXCLUDE_FROM_ALL的用处

本文详细介绍了CMake中的EXCLUDE_FROM_ALL属性的作用及使用方法。通过此属性可以将某些目标从默认构建中排除,从而提高编译速度。特别适用于不需要在正式版本中编译的测试代码。

cmake 的add_library,add_executable,add_subdirectory等命令都有一个EXCLUDE_FROM_ALL参数.
这个参数的作用根据cmake官网的解释就是如果某个target或subdirectory被设置为EXCLUDE_FROM_ALL属性,那么这个target(或这个subdirectory中的所有target)就会被排除在all target列表之外,这样,当执行默认的make(或nmake)时,这个target(或这个subdirectory中的所有target)就不会被编译。

EXCLUDE_FROM_ALL
Exclude the target from the all target.
A property on a target that indicates if the target is excluded from the default build target. If it is not, then with a Makefile for example typing make will cause this target to be built. The same concept applies to the default build of other generators. Installing a target with EXCLUDE_FROM_ALL set to true has undefined behavior.
@cmake.org

在一个项目中不可避免会有一些测试代码,这些测试代码,我们并不一定需要每次都编译,尤其是编译正式版本的时候,这些测试代码是不会加入release版本的。为了加快编译速度,可以将这些测试用的target或不会加入release的target 加上EXCLUDE_FROM_ALL属性就不需要每次编译它了。
下面是代码示例:

add_library(cmimpl SHARED ${CMIMPL_SOURCE_FILES})
add_library(cmjnidrv SHARED ${JNI_SOURCE_FILES})
# fctest指定了EXCLUDE_FROM_ALL 属性,不会自动编译,只能手动编译
add_executable(fctest EXCLUDE_FROM_ALL FeatureCompareSpeedTest.cpp)

加了EXCLUDE_FROM_ALL属性的target在默认编译的时候,不会被编译,如果要编译它们,需要手动编译,
比如make fctest指定编译名为fctest

参考:
https://cmake.org/cmake/help/v3.1/prop_tgt/EXCLUDE_FROM_ALL.html#prop_tgt:EXCLUDE_FROM_ALL

<think>我们正在讨论如何在CMake中使用`add_library`命令添加库文件。根据用户提供的引用,特别是引用[1]和引用[4],我们可以总结出`add_library`的基本用法以及如何添加不同类型的库(静态库、动态库等)。用户特别询问了如何添加外部库文件,这通常指的是已经预先编译好的库(而不是从源代码构建)。但是,需要注意的是,`add_library`命令通常用于从源代码构建库,而对于已经存在的外部预编译库,我们通常使用`add_library`的`IMPORTED`选项。因此,本回答将分为两部分:1.使用`add_library`从源代码构建库(这是该命令的主要用途)。2.使用`add_library`添加已存在的外部预编译库(使用`IMPORTED`选项)。同时,用户提供的引用中,引用[2]提到了Qt的`qt_add_library`,但用户的问题是关于CMake的`add_library`,因此我们主要关注原生CMake命令。下面开始详细说明:##1.使用`add_library`从源代码构建库###基本语法```cmakeadd_library(<name>[STATIC|SHARED|MODULE][EXCLUDE_FROM_ALL][<source>...])```-`<name>`:库的名称,在项目中唯一标识该库。-`[STATIC|SHARED|MODULE]`:指定库的类型。-`STATIC`:静态库(`.a`或`.lib`)-`SHARED`:动态库(`.so`或`.dll`)-`MODULE`:模块库(插件,通常不会被其他库或可执行文件链接,但可能在运行时动态加载)-`[EXCLUDE_FROM_ALL]`:如果设置,则该库不会被默认构建(除非明确指定或依赖它的目标被构建)。-`<source>...`:库的源文件列表(如`.cpp`,`.c`等)。###示例####创建静态库```cmakeadd_library(my_static_libSTATICsrc/file1.cppsrc/file2.cpp)```这将从两个源文件生成一个静态库`my_static_lib`(在Linux下为`libmy_static_lib.a`,Windows下为`my_static_lib.lib`)[^4]。####创建动态库```cmakeadd_library(my_shared_libSHAREDsrc/file1.cppsrc/file2.cpp)```生成动态库(在Linux下为`libmy_shared_lib.so`,Windows下为`my_shared_lib.dll`)。####创建对象库(ObjectLibrary)对象库是一种特殊类型的库,它不生成传统的库文件,而是将源文件编译成对象文件(`.o`或`.obj`),然后这些对象文件可以被其他目标使用。```cmakeadd_library(my_object_libOBJECTsrc/file1.cppsrc/file2.cpp)#然后可以在其他目标中使用这些对象文件add_executable(my_exemain.cpp$<TARGET_OBJECTS:my_object_lib>)#或者另一个库add_library(another_libSTATICother.cpp$<TARGET_OBJECTS:my_object_lib>)```对象库允许你将一组源文件编译成对象文件,然后在多个目标中重复使用,而不需要多次编译[^5]。##2.使用`add_library`添加外部预编译库(IMPORTED库)如果你有一个已经编译好的库(比如第三方库),你可以使用`IMPORTED`选项将其导入到CMake项目中。这样你就可以像使用自己构建的库一样链接它。###基本语法```cmakeadd_library(<name><type>IMPORTED[GLOBAL])```-`<name>`:导入库的目标名称。-`<type>`:库的类型,必须是`STATIC`、`SHARED`、`MODULE`或`UNKNOWN`之一。-`[GLOBAL]`:使导入的目标在全局范围内可见。然后,你需要使用`set_target_properties`命令指定库文件的位置以及头文件目录(如果需要)。###示例假设我们有一个预编译的静态库`mylib.lib`(Windows)或`libmylib.a`(Linux),以及头文件`mylib.h`。####导入静态库```cmake#添加导入库目标add_library(my_imported_libSTATICIMPORTED)#设置库文件的路径set_target_properties(my_imported_libPROPERTIESIMPORTED_LOCATION"/path/to/mylib.lib"#Windows#或者Linux下#IMPORTED_LOCATION"/path/to/libmylib.a")#如果头文件在另一个目录,可以设置包含目录target_include_directories(my_imported_libINTERFACE"/path/to/include")```####导入动态库```cmakeadd_library(my_imported_shared_libSHAREDIMPORTED)#设置动态库的位置set_target_properties(my_imported_shared_libPROPERTIESIMPORTED_LOCATION"/path/to/mylib.dll"#Windows动态库#对于Linux,可能是.so文件#IMPORTED_LOCATION"/path/to/libmylib.so")#如果是动态库,在Windows上可能还需要设置导入库(.lib)的位置#set_target_properties(my_imported_shared_libPROPERTIES#IMPORTED_IMPLIB"/path/to/mylib.lib"#)```###使用导入的库导入后,你可以像链接普通库一样链接它:```cmakeadd_executable(my_exemain.cpp)target_link_libraries(my_exePRIVATEmy_imported_lib)```##注意事项-对于导入的库,你需要确保路径正确,并且与构建配置(Debug/Release)匹配。有时需要为不同的配置设置不同的路径。-使用`find_package`命令查找系统库通常是更好的方法,因为它可以自动处理路径和依赖关系(如引用[3]中提到的那样)。但是,当库没有提供CMake配置文件时,使用`IMPORTED`目标是一个替代方案。##完整示例(导入预编译库)以下是一个完整的CMakeLists.txt示例,展示如何导入一个预编译的静态库并链接到可执行文件:```cmakecmake_minimum_required(VERSION3.10)project(MyProject)#添加可执行文件add_executable(my_exemain.cpp)#添加导入的静态库目标add_library(external_libSTATICIMPORTED)#设置库文件路径(注意:路径需要根据实际情况修改)set_target_properties(external_libPROPERTIESIMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/libs/libexternal.a#Linux示例#对于Windows,可能是${CMAKE_CURRENT_SOURCE_DIR}/libs/external.lib)#设置头文件目录(假设头文件在include目录下)target_include_directories(external_libINTERFACE${CMAKE_CURRENT_SOURCE_DIR}/include)#链接库target_link_libraries(my_exePRIVATEexternal_lib)```##总结-使用`add_library`可以从源代码构建静态库、动态库或对象库。-对于外部预编译库,使用`add_library`的`IMPORTED`选项创建导入目标,然后设置`IMPORTED_LOCATION`属性指定库文件路径,并使用`target_include_directories`添加头文件路径。-导入库后,使用`target_link_libraries`链接到目标。##相关问题1.如何在CMake中同时支持静态库和动态库的构建?2.导入库时如何区分Debug和Release版本?3.对象库(ObjectLibrary)有什么优势和使用场景?4.如何为导入的库设置其他属性(如编译选项、定义等)?5.在跨平台项目中,如何管理不同平台下的预编译库路径?</think>### 如何在 CMake 中使用 `add_library` 添加库文件 `add_library` 是 CMake 的核心命令,用于创建和管理库文件。根据使用场景可分为以下类型: #### 一、创建新库(从源代码构建) **1. 静态库(STATIC)** 编译为 `.a`(Linux)或 `.lib`(Windows)文件,链接时完整复制到可执行文件中。 ```cmake add_library(my_static_lib STATIC src/file1.cpp src/file2.cpp # 指定源文件 ) ``` 特点: - 文件体积较大但运行时无外部依赖 - 适用场景:封闭系统、嵌入式开发[^4] **2. 动态库(SHARED)** 编译为 `.so`(Linux)或 `.dll`(Windows)文件,运行时加载。 ```cmake add_library(my_shared_lib SHARED src/class.cpp src/utils.cpp ) ``` **3. 对象库(OBJECT)** 仅编译对象文件(`.o`),不打包成库,可被多个目标复用: ```cmake add_library(my_objects OBJECT a.cpp b.cpp) # 创建对象文件 add_executable(app main.cpp $<TARGET_OBJECTS:my_objects>) # 链接对象文件 add_library(combined_lib STATIC c.cpp $<TARGET_OBJECTS:my_objects>) # 复用对象[^5] ``` **4. 接口库(INTERFACE)** 不包含源文件,仅传递依赖(如头文件目录、编译选项): ```cmake add_library(my_headers INTERFACE) target_include_directories(my_headers INTERFACE include/) # 传递头文件路径 ``` --- #### 二、添加外部预编译库(IMPORTED) **适用于已存在的 `.a/.so/.lib/.dll` 文件** ```cmake # 添加导入库目标 add_library(external_lib STATIC IMPORTED) # 设置库文件路径 set_target_properties(external_lib PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/libs/libexternal.a" # Linux/Mac # IMPORTED_LOCATION "C:/libs/external.lib" # Windows路径格式 ) # 链接到可执行文件 add_executable(my_app main.cpp) target_link_libraries(my_app PRIVATE external_lib) ``` --- #### 三、特殊类型库 **1. 别名库(ALIAS)** 为目标库创建别名: ```cmake add_library(real_lib STATIC src.cpp) add_library(my_alias ALIAS real_lib) # 创建别名 ``` **2. Qt 专用库(需 Qt 环境)** ```cmake qt_add_library(qt_lib STATIC # 自动处理Qt元对象系统 qrc_resources.qrc gui_window.cpp )[^2] ``` --- ### 关键技巧与注意事项 1. **路径处理** - 使用 `${CMAKE_CURRENT_SOURCE_DIR}` 确保路径正确性 - 跨平台示例: ```cmake set(LIB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libs) if(WIN32) set(LIB_FILE "${LIB_PATH}/mylib.lib") else() set(LIB_FILE "${LIB_PATH}/libmylib.a") endif() ``` 2. **依赖管理** ```cmake target_link_libraries(my_app PRIVATE my_static_lib # 私有依赖 PUBLIC external_lib # 传递依赖 INTERFACE my_headers # 接口依赖 ) ``` 3. **最佳实践** - 优先使用 `target_include_directories()` 而非全局 `include_directories()` - 用 `$<TARGET_OBJECTS:...>` 复用对象文件减少编译时间[^5] - 导入库时显式指定 `STATIC/SHARED` 类型避免歧义 > **常见错误处理**: > - *"未定义引用"*:检查是否遗漏 `target_link_libraries` > - *"找不到库文件"*:验证 `IMPORTED_LOCATION` 路径是否包含文件扩展名 > - *Qt 链接错误*:确保先调用 `find_package(Qt6 REQUIRED COMPONENTS Core Gui)` --- ### 完整示例 ```cmake cmake_minimum_required(VERSION 3.20) project(my_project) # 创建静态库 add_library(app_lib STATIC src/lib_math.cpp) # 导入预编译库 add_library(third_party_lib SHARED IMPORTED) set_target_properties(third_party_lib PROPERTIES IMPORTED_LOCATION "libs/libthird.so" ) # 创建可执行文件并链接库 add_executable(main_app main.cpp) target_link_libraries(main_app PRIVATE app_lib PUBLIC third_party_lib ) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值