如何为不同CMake目标构建带有不同编译选项的库?
为特定程序定制库的编译选项
当然可以实现!在CMake里有几种不同的方案可以满足你这个需求,我给你详细讲讲最常用的几个:
方案一:为每个程序创建库的专用变体
这是最直观的方式——针对每个需要特殊编译选项的程序,单独创建一个库的目标,给每个目标设置专属的包含目录(或其他编译选项),然后分别链接到对应的程序。
示例代码:
# 针对程序A的库变体,设置包含目录A add_library(MyLib_A STATIC src/lib.cpp) target_include_directories(MyLib_A PRIVATE include/A) # 针对程序B的库变体,设置包含目录B add_library(MyLib_B STATIC src/lib.cpp) target_include_directories(MyLib_B PRIVATE include/B) # 程序A链接专属的库变体 add_executable(ProgramA src/progA.cpp) target_link_libraries(ProgramA PRIVATE MyLib_A) # 程序B链接专属的库变体 add_executable(ProgramB src/progB.cpp) target_link_libraries(ProgramB PRIVATE MyLib_B)
这个方案的优点是逻辑清晰,每个库变体完全独立,不会出现编译选项互相干扰的问题。缺点是如果库的代码量很大,会重复编译多次,增加整体构建时间。
方案二:用对象库避免重复编译
如果你不想重复编译库的核心代码,可以用CMake的**对象库(Object Library)**特性:先把库的代码编译成目标文件集合,再基于这些对象文件创建不同的库变体,每个变体可以设置自己的专属编译选项。
示例代码:
# 先创建对象库,编译库的核心代码(只编译一次) add_library(MyLib_Objects OBJECT src/lib.cpp) # 这里可以设置所有变体共享的公共编译选项,比如公共包含目录 target_include_directories(MyLib_Objects PUBLIC include/common) # 基于对象库创建程序A的专属库,添加包含目录A add_library(MyLib_A STATIC) target_sources(MyLib_A PRIVATE $<TARGET_OBJECTS:MyLib_Objects>) target_include_directories(MyLib_A PRIVATE include/A) # 基于对象库创建程序B的专属库,添加包含目录B add_library(MyLib_B STATIC) target_sources(MyLib_B PRIVATE $<TARGET_OBJECTS:MyLib_Objects>) target_include_directories(MyLib_B PRIVATE include/B) # 链接程序到对应的库变体 add_executable(ProgramA src/progA.cpp) target_link_libraries(ProgramA PRIVATE MyLib_A) add_executable(ProgramB src/progB.cpp) target_link_libraries(ProgramB PRIVATE MyLib_B)
这种方式既保留了每个库变体的独立性,又避免了重复编译核心代码,平衡了构建效率和灵活性。
方案三:直接为程序添加专属选项(适合非库依赖的场景)
如果你的包含目录是程序特有的,库本身的代码并不依赖这些目录,那可以不用创建多个库变体,直接给每个程序添加专属的包含目录,再链接同一个基础库即可。
示例代码:
# 基础库,设置公共的编译选项和包含目录 add_library(MyLib STATIC src/lib.cpp) target_include_directories(MyLib PUBLIC include/common) # 程序A添加自己的专属包含目录,链接基础库 add_executable(ProgramA src/progA.cpp) target_include_directories(ProgramA PRIVATE include/A) target_link_libraries(ProgramA PRIVATE MyLib) # 程序B添加自己的专属包含目录,链接基础库 add_executable(ProgramB src/progB.cpp) target_include_directories(ProgramB PRIVATE include/B) target_link_libraries(ProgramB PRIVATE MyLib)
这个方案最简单,但只适用于库代码不依赖专属目录的场景——如果库的编译结果需要根据不同目录下的头文件变化,那前面两种方案更合适。
额外注意点
- 如果使用动态库(SHARED),不建议创建多个库变体,因为动态库是全局的,多个同名(或不同名但逻辑冲突)的动态库可能导致运行时问题,这种场景下静态库是更安全的选择。
- 除了包含目录,
target_compile_options、target_compile_definitions等其他编译相关的属性,也可以用同样的方式为每个库变体或程序单独设置。
内容的提问来源于stack exchange,提问作者Vitaliy Hramchenko
相关产品推荐
相关产品推荐

