C++ 在CMAKE中使用具有静态依赖项的库
CMake中有没有一种方法可以将库用于具有不同静态依赖关系的多个目标? 为了更好地解释它,请考虑这个最小的例子:我想要两个可执行文件:第一个应该打印“是”,第二个应该打印“否”。为此,我使用图书馆的“printsh”,它打印“something”。它打印的字符串来自“用户”(printyes或printno)提供的头文件。这看起来是这样的:C++ 在CMAKE中使用具有静态依赖项的库,c++,cmake,header,dependencies,static-libraries,C++,Cmake,Header,Dependencies,Static Libraries,CMake中有没有一种方法可以将库用于具有不同静态依赖关系的多个目标? 为了更好地解释它,请考虑这个最小的例子:我想要两个可执行文件:第一个应该打印“是”,第二个应该打印“否”。为此,我使用图书馆的“printsh”,它打印“something”。它打印的字符串来自“用户”(printyes或printno)提供的头文件。这看起来是这样的: ├── apps │ ├── printno │ │ ├── CMakeLists.txt │ │ │ add_execut
├── apps
│ ├── printno
│ │ ├── CMakeLists.txt
│ │ │ add_executable(printno main.cpp)
│ │ │ target_link_libraries(printno PRIVATE printsth)
│ │ │
│ │ ├── main.cpp
│ │ │ #include "printsth/printsth.h"
│ │ │
│ │ │ int main() {
│ │ │ printsth();
│ │ │ return 0;
│ │ │ }
│ │ │
│ │ └── print_usr.h
│ │ #define USR_STRING "NO"
│ │
│ └── printyes
│ │ ├── CMakeLists.txt
│ │ │ add_executable(printyes main.cpp)
│ │ │ target_link_libraries(printyes PRIVATE printsth)
│ │ │
│ │ ├── main.cpp
│ │ │ #include "printsth/printsth.h"
│ │ │
│ │ │ int main() {
│ │ │ printsth();
│ │ │ return 0;
│ │ │ }
│ │ │
│ │ └── print_usr.h
│ │ #define USR_STRING "YES"
│ │
├── extern
│ └── printsh
│ ├── include
│ │ └── printsh
│ │ └── printsh.h
│ │ void printsth();
│ │
│ ├── src
│ │ ├── CMakeLists.txt
│ │ │ add_library(printsth printsth.cpp)
│ │ │ target_include_directories(printsth PUBLIC ../include)
│ │ │
│ │ └── printsh.cpp
│ │ #include "printsth/printsth.h"
│ │ #include "print_usr.h"
│ │ #include <iostream>
│ │
│ │ void printsth() {
│ │ std::cout << USR_STRING << std::endl;
│ │ }
│ │
│ └── CMakeLists.txt
│ cmake_minimum_required(VERSION 3.11...3.16)
│
│ project(printsh
│ VERSION 0.1
│ DESCRIPTION "Print something"
│ LANGUAGES CXX)
│
│ add_subdirectory(src)
│
└── CMakeLists.txt
cmake_minimum_required(VERSION 3.11...3.16)
project(printexamples
VERSION 0.1
DESCRIPTION "Print examples"
LANGUAGES CXX)
add_subdirectory(apps/printyes)
add_subdirectory(apps/printno)
add_subdirectory(extern/printsth)
那么,我能告诉CMake在为printno构建printsh lib时使用apps/printno作为include目录,在为printyes构建printsh lib时使用apps/printyes作为include目录吗
我知道这个例子没有多大意义,可以很容易地去掉标题依赖项(例如,将自定义字符串作为参数传递给printsh()),并且一切都很好。因此,这只是一个演示“现实世界”问题的示例,我无法轻松摆脱依赖关系。在CMake意义上,库目标表示一次编译的库,但可以链接到多个目标(可执行库或其他库) 由于无法将两个宏定义编译到单个库中,因此需要为每个定义集创建不同的库目标。也就是说,您需要创建两个库 对于重复的命令序列,CMake提供宏和函数,并使用不同的参数多次调用它们 您还可以创建一个“参数化的”
CMakeLists.txt
,并(通过add_子目录
)多次“调用”它:
extern/printsh/src/CMakeLists.txt:
# Requires 'printsth_target' and 'printish_usr_dir' variables to be set.
# The first variable denotes name of the target created,
# the second variable denotes include directory with 'print_usr.h' header.
if (NOT printsth_target)
message(FATAL_ERROR "printsth_target variable is required but is not set.")
endif()
if (NOT printish_usr_dir)
message(FATAL_ERROR "printish_usr_dir variable is required but is not set.")
endif()
# Create a library target with user-provided name
add_library(${printsth_target} printsth.cpp)
target_include_directories(${printsth_target} PUBLIC ../include)
# Add user-provided include directory
target_include_directories(${printsth_target} PRIVATE ${printish_usr_dir})
add_executable(printno main.cpp)
# Instantiate 'printsth' library with needed parameters.
set(printsth_target "printsh_no")
set(printish_usr_dir ${CMAKE_CURRENT_SOURCE_DIR})
# Need to specify the second argument - build directory, where the library will be built.
add_subdirectory(../../extern/printsh printsh_no_dir)
# No we can link with a library. Use a name, specified for 'printsth_target' variable.
target_link_libraries(printno PRIVATE printsh_no)
# <...>
add_subdirectory(apps/printyes)
add_subdirectory(apps/printno)
# Uncommenting the following line causes FATAL_ERROR triggered.
#add_subdirectory(extern/printsth)
使用这种脚本,printsh
库可以在应用程序的CMakeLists.txt
中实例化
apps/printno/CMakeLists.txt:
# Requires 'printsth_target' and 'printish_usr_dir' variables to be set.
# The first variable denotes name of the target created,
# the second variable denotes include directory with 'print_usr.h' header.
if (NOT printsth_target)
message(FATAL_ERROR "printsth_target variable is required but is not set.")
endif()
if (NOT printish_usr_dir)
message(FATAL_ERROR "printish_usr_dir variable is required but is not set.")
endif()
# Create a library target with user-provided name
add_library(${printsth_target} printsth.cpp)
target_include_directories(${printsth_target} PUBLIC ../include)
# Add user-provided include directory
target_include_directories(${printsth_target} PRIVATE ${printish_usr_dir})
add_executable(printno main.cpp)
# Instantiate 'printsth' library with needed parameters.
set(printsth_target "printsh_no")
set(printish_usr_dir ${CMAKE_CURRENT_SOURCE_DIR})
# Need to specify the second argument - build directory, where the library will be built.
add_subdirectory(../../extern/printsh printsh_no_dir)
# No we can link with a library. Use a name, specified for 'printsth_target' variable.
target_link_libraries(printno PRIVATE printsh_no)
# <...>
add_subdirectory(apps/printyes)
add_subdirectory(apps/printno)
# Uncommenting the following line causes FATAL_ERROR triggered.
#add_subdirectory(extern/printsth)
应修改顶层CMakeLists.txt
,以便不实例化库
CMakeLists.txt:
# Requires 'printsth_target' and 'printish_usr_dir' variables to be set.
# The first variable denotes name of the target created,
# the second variable denotes include directory with 'print_usr.h' header.
if (NOT printsth_target)
message(FATAL_ERROR "printsth_target variable is required but is not set.")
endif()
if (NOT printish_usr_dir)
message(FATAL_ERROR "printish_usr_dir variable is required but is not set.")
endif()
# Create a library target with user-provided name
add_library(${printsth_target} printsth.cpp)
target_include_directories(${printsth_target} PUBLIC ../include)
# Add user-provided include directory
target_include_directories(${printsth_target} PRIVATE ${printish_usr_dir})
add_executable(printno main.cpp)
# Instantiate 'printsth' library with needed parameters.
set(printsth_target "printsh_no")
set(printish_usr_dir ${CMAKE_CURRENT_SOURCE_DIR})
# Need to specify the second argument - build directory, where the library will be built.
add_subdirectory(../../extern/printsh printsh_no_dir)
# No we can link with a library. Use a name, specified for 'printsth_target' variable.
target_link_libraries(printno PRIVATE printsh_no)
# <...>
add_subdirectory(apps/printyes)
add_subdirectory(apps/printno)
# Uncommenting the following line causes FATAL_ERROR triggered.
#add_subdirectory(extern/printsth)
#
添加子目录(apps/printyes)
添加子目录(apps/printno)
#取消对以下行的注释会触发致命的\u错误。
#添加子目录(extern/printsth)
您的意思是像cmake中的if else这样的东西吗?库不是“为…而构建”的,它只是构建一次,然后与其他模块链接在一起。CMake不会改变库的工作方式。欢迎使用堆栈溢出!这是一个很棒的第一个问题!要做到这一点,除了完全重新设计以删除依赖项之外,还有一种方法是创建printsh
库的“是”和“否”版本。然后,将库的正确“是”或“否”版本链接到printyes
和printno
。谢谢您的评论。我看到它实际上不是一个真正的静态库@squareskittles问题是,在“现实”中,这可能是相当多的不同版本,我想保持libraray(printsh)独立于配置。另一种方法是将库源直接包含到可执行文件中,但我看不到任何方法仍然能够控制库源文件的导入路径等。感谢您的详细回答!这正是我要找的。我唯一没有真正了解的部分是add_subdirectory()的作用以及为什么它是必需的(如果我构建了一个标准的、非参数化的libraray,我不必使用add_subdirectory())。在原始代码中,您在根CMakeLists.txt
中使用add_subdirectory(extern/printsh)
来实例化(构建)库。在我的变体中,apps/printno/CMakeLists.txt
和apps/printyes/CMakeLists.txt
中有两个这样的调用(后一个文件与前一个文件类似,因此未显示)。