包含子库的现代CMake库
我有几个库(子项目)作为一个主库的一部分。如何在“主库”(a)中聚合子库(b) 目标是只拥有一个库包含子库的现代CMake库,cmake,Cmake,我有几个库(子项目)作为一个主库的一部分。如何在“主库”(a)中聚合子库(b) 目标是只拥有一个库a,并按如下方式使用子库#include (有没有一种方法可以让include路径如下:#include?) 假设文件夹结构如下: a |-- CMakeLists.txt |-- aConfig.cmake `-- b |-- CMakeLists.txt |-- include | `-- b | `-- b.h `-- src
a
,并按如下方式使用子库#include
(有没有一种方法可以让include路径如下:#include
?)
假设文件夹结构如下:
a
|-- CMakeLists.txt
|-- aConfig.cmake
`-- b
|-- CMakeLists.txt
|-- include
| `-- b
| `-- b.h
`-- src
`-- b.cpp
我有以下库a
,具体取决于库b
。必须安装库a
,然后使用find\u包(需要配置)
命令以现代的CMake方式找到库。该库不提供任何实现,但应聚合子库。我认为将目标包含目录
公开
会将接口包含目录
属性传播到库a
,因为它链接到b
,但我无法使其工作:
cmake_minimum_required(VERSION 3.0.2)
project(a)
find_package(Eigen3 3.2.2 REQUIRED)
add_subdirectory(b)
## Build
add_library(a)
add_library(a::a ALIAS a)
target_link_library(a
PUBLIC
b::b
)
## Install
include(GNUInstallDirs)
# create export set
install(TARGETS a
EXPORT "aTargets"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
)
install(
DIRECTORY
b/include/
DESTINATION
"${CMAKE_INSTALL_INCLUDEDIR}"
)
install(EXPORT "${PROJECT_NAME}Targets"
FILE
"aTargets.cmake"
NAMESPACE
"a::"
DESTINATION
lib/cmake/a
)
install(
FILES
"aConfig.cmake"
DESTINATION
"lib/cmake/a"
)
它将要求您更改目录结构。标头包含绑定到物理路径,并且没有类似于
a/b/b.h
的物理路径。解决方案是使用以下内容更改目录结构:
a
|-- CMakeLists.txt
|-- aConfig.cmake
`-- b
|-- CMakeLists.txt
|-- include
| `-- a
| `-- b
| `-- b.h
`-- src
`-- b.cpp
并将目标include目录设置为a/b/include
与一起使用似乎可以解决您的问题。下面是一个简单的工作示例
假设我们有以下目录结构
.
├── a
│ ├── b
│ │ ├── CMakeLists.txt
│ │ ├── include
│ │ │ └── b
│ │ │ └── b.h
│ │ └── src
│ │ └── b.cpp
│ ├── c
│ │ ├── CMakeLists.txt
│ │ ├── include
│ │ │ └── c
│ │ │ └── c.h
│ │ └── src
│ │ └── c.cpp
│ └── CMakeLists.txt
├── CMakeLists.txt
└── main.cpp
9 directories, 9 files
其中a
是包含其他子项目的超级项目。b
和c
库的内容如下:
# a/b/CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project(b CXX)
add_library(b
include/b/b.h
src/b.cpp
)
add_library(b::b ALIAS b)
target_include_directories(b
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
install(TARGETS
b
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
)
install(DIRECTORY include/b DESTINATION include)
/* a/b/include/b/b.h */
#ifdef __cplusplus
extern "C" {
#endif
double funcb(const double);
#ifdef __cplusplus
}
#endif
/* a/b/src/b.cpp */
#include "b/b.h"
extern "C" {
double funcb(const double x) { return x + x; }
}
# a/c/CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project(c CXX)
add_library(c
include/c/c.h
src/c.cpp
)
add_library(c::c ALIAS c)
target_include_directories(c
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
install(TARGETS
c
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
)
install(DIRECTORY include/c DESTINATION include)
/* a/c/include/c/c.h */
#ifdef __cplusplus
extern "C" {
#endif
double funcc(const double);
#ifdef __cplusplus
}
#endif
/* a/c/src/c.cpp */
#include "c/c.h"
extern "C" {
double funcc(const double x) { return x * x; }
}
# a/CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project(a)
add_subdirectory(b)
add_subdirectory(c)
add_library(a INTERFACE)
add_library(a::a ALIAS a)
target_link_libraries(a
INTERFACE
b::b
c::c
)
最后,您的应用程序将一如既往地使用b
和c
库:
#include <iostream>
using namespace std;
#include "b/b.h"
#include "c/c.h"
int main(int argc, char* argv[]) {
cout << funcb(5) << '\n';
cout << funcc(5) << '\n';
return 0;
}
我希望这能解决您的问题。我已经想到了这一点,但不想妥协,因为b子组件需要了解a。我刚刚将子库源和头添加到库
a
,并将头安装在include/grid\u map/
中,与其他include一起。这是非常肮脏和丑陋的,但由于库是一个ROS包的分支,我希望尽可能少地分散文件夹结构。如果有一种聚合库的方法,那就太好了。我可以接受原始的include路径。当您找到包(a)
(我假设您正在使用它而不是“超级构建”)时,您希望在a
的消费者中继续使用\include
,还是希望使用\include
?我无法理解你在括号中的意思。#include
将与子项目的include路径一致,并且如果只包含消息的一部分,则允许一致使用。主要思想是只链接一个库a
,并使用所有子项目的库。我希望这能解决你的问题。这正是我想要的。我一开始工作就回来。需要做一些其他的事情,而我丑陋的工作环境也允许同样的用法。谢谢你的详细回答!
cmake_minimum_required(VERSION 3.9)
project(app)
add_subdirectory(a)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE a::a)