设置子模块目标的输出目录时,在 CMAKE_BINARY_DIR 和 PROJECT_BINARY_DIR 之间进行权衡
Tradeof between CMAKE_BINARY_DIR and PROJECT_BINARY_DIR when setting submodule targets' output directories
我正在开发一个将被另一个项目使用的库。主项目使用几个链接为 git 子模块 的库。在用作子模块的库项目中,我可以用两种不同的方式设置 LIBRARY_OUTPUT_DIRECTORY
和 ARCHIVE_OUTPUT_DIRECTORY
。
在选项 A 中,使用 ${PROJECT_BINARY_DIR}/lib
构建目标并保存到它们自己的子目录中,但在 选项 B 中所有目标都已构建并保存到 ${CMAKE_BINARY_DIR}/lib
目录。
这也可以扩展到由子模块构建的二进制文件。因此,这两个选项中的哪一个 scale 更好/通常用作最佳实践?
选项A
CMakeLists.txt
# Set target properties
set_target_properties(${PROJECT_NAME}_lib_shared PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set_target_properties(${PROJECT_NAME}_lib_static PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib/static)
文件夹结构
.
+-- build
| +-- bin
| +-- MainProject
| +-- test
| +-- lib
| +-- SubModuleA
| +-- SubModuleA_lib_shared.a
| +-- static
| +-- SubModuleA_lib_static.so
| +-- SubModuleB
| +-- SubModuleB_lib_shared.a
| +-- static
| +-- SubModuleB_lib_static.so
+-- lib
| +-- SubModuleA
| | +-- CMakeLists.txt
| +--- SubModuleB
| | +-- CMakeLists.txt
+-- inc
| +-- foo.h
+-- src
| +-- foo.cpp
| +-- main.cpp
| +-- CMakeLists.txt
+-- test
| +-- test.cpp
| +-- CMakeLists.txt
+-- CMakeLists.txt
选项 B
CMakeLists.txt
# Set target properties
set_target_properties(${PROJECT_NAME}_lib_shared PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set_target_properties(${PROJECT_NAME}_lib_static PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/static)
文件夹结构
.
+-- build
| +-- bin
| +-- MainProject
| +-- test
| +-- lib
| +-- SubModuleA_lib_shared.a
| +-- SubModuleB_lib_shared.a
| +-- static
| +-- SubModuleA_lib_static.so
+-- SubModuleB_lib_static.so
+-- lib
| +-- SubModuleA
| | +-- CMakeLists.txt
| +--- SubModuleB
| | +-- CMakeLists.txt
+-- inc
| +-- foo.h
+-- src
| +-- foo.cpp
| +-- main.cpp
| +-- CMakeLists.txt
+-- test
| +-- test.cpp
| +-- CMakeLists.txt
+-- CMakeLists.txt
除非有充分的理由,否则根本不应在库项目中为目标设置输出目录。如果消费者 link 访问库项目提供的 CMake 目标,那么他们通常甚至不需要知道这些库的确切位置,即使他们知道,他们也可以通过 target-dependent generator-expressions.
此外,即使您确实有充分的理由(例如,因为您想在 CI 构建中存档构建工件并且还没有使用 CPack 生成正确的包),您仍然不应该将您的设置强加给消费者。如果您允许消费者轻松覆盖默认设置,例如使用该机制确保共享库将位于其项目构建的二进制文件旁边,这是 Windows 到 运行 可执行文件所必需的,而无需手动修改 PATH 以包含依赖项所在的所有目录位于,即消费者可以通过更改库目标的默认输出目录来确保可执行文件可以来自构建树 运行。
因此您不应设置目标属性,而应通过设置
来设置这些属性的默认值
if (NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib/static")
endif()
if (NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
endif()
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
endif()
让消费者更方便地一次更改所有目标的输出位置,而无需再次为每个目标手动设置属性。
那么你用${PROJECT_BINARY_DIR}
还是${CMAKE_BINARY_DIR}
在很大程度上是无关紧要的,但我个人更喜欢使用${PROJECT_BINARY_DIR}
因为它确保不会有冲突,即使两个子项目选择了它们的目标名称相同(例如,多个目标可能定义了一个名为 tests
的可执行文件)。
我正在开发一个将被另一个项目使用的库。主项目使用几个链接为 git 子模块 的库。在用作子模块的库项目中,我可以用两种不同的方式设置 LIBRARY_OUTPUT_DIRECTORY
和 ARCHIVE_OUTPUT_DIRECTORY
。
在选项 A 中,使用 ${PROJECT_BINARY_DIR}/lib
构建目标并保存到它们自己的子目录中,但在 选项 B 中所有目标都已构建并保存到 ${CMAKE_BINARY_DIR}/lib
目录。
这也可以扩展到由子模块构建的二进制文件。因此,这两个选项中的哪一个 scale 更好/通常用作最佳实践?
选项A
CMakeLists.txt
# Set target properties
set_target_properties(${PROJECT_NAME}_lib_shared PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set_target_properties(${PROJECT_NAME}_lib_static PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib/static)
文件夹结构
.
+-- build
| +-- bin
| +-- MainProject
| +-- test
| +-- lib
| +-- SubModuleA
| +-- SubModuleA_lib_shared.a
| +-- static
| +-- SubModuleA_lib_static.so
| +-- SubModuleB
| +-- SubModuleB_lib_shared.a
| +-- static
| +-- SubModuleB_lib_static.so
+-- lib
| +-- SubModuleA
| | +-- CMakeLists.txt
| +--- SubModuleB
| | +-- CMakeLists.txt
+-- inc
| +-- foo.h
+-- src
| +-- foo.cpp
| +-- main.cpp
| +-- CMakeLists.txt
+-- test
| +-- test.cpp
| +-- CMakeLists.txt
+-- CMakeLists.txt
选项 B
CMakeLists.txt
# Set target properties
set_target_properties(${PROJECT_NAME}_lib_shared PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set_target_properties(${PROJECT_NAME}_lib_static PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/static)
文件夹结构
.
+-- build
| +-- bin
| +-- MainProject
| +-- test
| +-- lib
| +-- SubModuleA_lib_shared.a
| +-- SubModuleB_lib_shared.a
| +-- static
| +-- SubModuleA_lib_static.so
+-- SubModuleB_lib_static.so
+-- lib
| +-- SubModuleA
| | +-- CMakeLists.txt
| +--- SubModuleB
| | +-- CMakeLists.txt
+-- inc
| +-- foo.h
+-- src
| +-- foo.cpp
| +-- main.cpp
| +-- CMakeLists.txt
+-- test
| +-- test.cpp
| +-- CMakeLists.txt
+-- CMakeLists.txt
除非有充分的理由,否则根本不应在库项目中为目标设置输出目录。如果消费者 link 访问库项目提供的 CMake 目标,那么他们通常甚至不需要知道这些库的确切位置,即使他们知道,他们也可以通过 target-dependent generator-expressions.
此外,即使您确实有充分的理由(例如,因为您想在 CI 构建中存档构建工件并且还没有使用 CPack 生成正确的包),您仍然不应该将您的设置强加给消费者。如果您允许消费者轻松覆盖默认设置,例如使用该机制确保共享库将位于其项目构建的二进制文件旁边,这是 Windows 到 运行 可执行文件所必需的,而无需手动修改 PATH 以包含依赖项所在的所有目录位于,即消费者可以通过更改库目标的默认输出目录来确保可执行文件可以来自构建树 运行。
因此您不应设置目标属性,而应通过设置
来设置这些属性的默认值if (NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib/static")
endif()
if (NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
endif()
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
endif()
让消费者更方便地一次更改所有目标的输出位置,而无需再次为每个目标手动设置属性。
那么你用${PROJECT_BINARY_DIR}
还是${CMAKE_BINARY_DIR}
在很大程度上是无关紧要的,但我个人更喜欢使用${PROJECT_BINARY_DIR}
因为它确保不会有冲突,即使两个子项目选择了它们的目标名称相同(例如,多个目标可能定义了一个名为 tests
的可执行文件)。