我有几个项目(git repos),每个项目都依赖于一些库(也是git repos)。每个项目只有一个目标可执行文件,并链接来自其他repos的库。
文件结构:
├── libraries
│ ├── libraryX (git:master)
│ │ ├── build
│ │ │ └── libX.so
│ │ ├── CMakeLists.txt
│ │ ├── fileX.cpp
│ │ └── fileX.h
│ ├── libraryY (git:master)
│ │ ├── build
│ │ │ └── libY.so
│ │ ├── CMakeLists.txt
│ │ ├── fileY.cpp
│ │ └── fileY.h
│ └── libraryZ (git:master)
│ ├── build
│ │ └── libZ.so
│ ├── CMakeLists.txt
│ ├── fileZ.cpp
│ └── fileZ.h
└── projects
├── projectA (git:master)
│ ├── build
│ │ └── outA
│ ├── CMakeLists.txt
│ └── mainA.cpp
└── projectB (git:master)
├── build
│ └── outB
├── CMakeLists.txt
└── mainB.cpp
这是libraryX
中CMakeLists.txt
文件的示例:
cmake_minimum_required(VERSION 3.6)
project(libraryX LANGUAGES CXX)
set(libraries $ENV{LIBRARIES})
set(projects $ENV{PROJECTS})
add_library(libX SHARED fileX.cpp)
target_include_directories(libX PUBLIC ${libraries}/libraryX/)
目前我正在手动构建每个库,生成*.so
文件,然后我去项目并构建可执行文件。这是projectA
内部的CMakeLists.txt
示例:
cmake_minimum_required(VERSION 3.6)
project(projectA LANGUAGES CXX)
set(libraries $ENV{LIBRARIES})
set(projects $ENV{PROJECTS})
add_executable(outA mainA.cpp)
target_include_directories(outA
PUBLIC
${libraries}/libraryX/
${libraries}/libraryY/
${libraries}/libraryZ/
${projects}/projectA/
)
target_link_libraries(outA
${libraries}/libraryX/build/libX.so
${libraries}/libraryY/build/libY.so
${libraries}/libraryZ/build/libZ.so
)
我只对一次构建/运行一个项目(例如projectA/
)感兴趣,但是我不想每次都手动预编译每个库我做改变。
另外,我不能在项目下移动libraries/
(例如projectA/libraries/libraryX
),因为projectB/
也依赖于它们,我不喜欢在兄弟文件夹中的一台计算机中有相同存储库的两个克隆。我也不能更改和重新安排存储库的内容以适应自己的需要,因为不同的团队正在开发它们,并计划在将来将它们作为完整的包发布,可从apt-get安装。最后,我不想在工作区中使用单个顶级CMakeLists.txt
,因为项目a和B彼此独立。
我尝试查看add_subdirectory
和target_sources
,但无法理解如何目标源,如果我想要相同的库在projectA
和projectB
中由不同的可执行文件使用。
当然,我可以运行bash脚本在每个库中构建CMake,但我认为这是CMake的工作。我显然没有看到什么明显的解决办法。
谁能帮助我强迫CMake预编译库之前链接到目标?
谢谢!
注:我怎么能告诉CMake编译*.dll
文件而不是*.so
,和*.exe
而不是Linux二进制文件?
我已经阅读和观看了很多教程,并阅读了很多关于CMake项目架构的stackoverflow答案。我试着在Windows上的Visual Studio中运行这个项目,希望它能自己解决这个问题——但并没有什么帮助。我写了一个bash脚本,在链接库之前编译它们,但感觉不对,因为我被承诺CMake实际上为我做了这件事。我也尝试使用子目录系统,正如在另一个stackoverflow回答中提到的,但它并没有真正成功。
您的libraryX/CMakeLists.txt
应该是这样的:
cmake_minimum_required(VERSION 3.6)
project(libraryX LANGUAGES CXX)
add_library(libX SHARED fileX.cpp)
target_include_directories(
libX
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
在所有子项目的根目录中,您可以添加CMakeLists.txt
,它对所有库(第一个)和二进制文件(最后一个)执行add_subdirectory()
。
然后在projectX/CMakeLists.txt
中链接到你需要的CMake目标:
cmake_minimum_required(VERSION 3.6)
project(projectX LANGUAGES CXX)
add_executable(outA mainA.cpp)
target_include_directories(
outA
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
# NOTE No need for any other paths
)
target_link_libraries(
outA
PRIVATE
libX
libY
libZ
)
更新(在我发现这些是独立的git仓库之后):
您需要导出您的库目标(构建并安装到相同的前缀中),并在projectX/CMakeLists.txt
中使用find_package(libX)
来查找要链接的目标。拥有独立的库是很好的(与单一库相比;)。