我有几个库(子项目)作为一个主库的一部分。如何将子库(b)汇总到“主库”(a)中?
目标是仅拥有一个图书馆a
并按如下方式使用子图书馆#include <b/b.h>
(有一种如下包含路径的方法:#include <a/b/b.h>
吗?)
假设以下文件夹结构:
a
|-- CMakeLists.txt
|-- aConfig.cmake
`-- b
|-- CMakeLists.txt
|-- include
| `-- b
| `-- b.h
`-- src
`-- b.cpp
我有以下库a
,具体取决于库b
。必须安装库a
,并以现代CMake方式使用find_package(a CONFIG REQUIRED)
命令找到该库。该库不提供任何实现,但应汇总这些子库。我以为制作target_include_directories
Public
会将INTERFACE_INCLUDE_DIRECTORIES
属性传播到库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"
)
答案 0 :(得分:1)
这将要求您更改目录结构。标头包含与物理路径相关,并且没有类似于a/b/b.h
的物理路径。解决方案是使用以下方式更改目录结构:
a
|-- CMakeLists.txt
|-- aConfig.cmake
`-- b
|-- CMakeLists.txt
|-- include
| `-- a
| `-- b
| `-- b.h
`-- src
`-- b.cpp
并将目标包含目录设置为a/b/include
答案 1 :(得分:1)
同时使用interface libraries和relocatable packages可以解决您的问题。下面是一个最小的工作示例。
假设我们具有以下目录结构
.
├── 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
变成INTERFACE
库,如下所示:
# 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;
}
,相应的CMakeLists.txt
将显示
cmake_minimum_required(VERSION 3.9)
project(app)
add_subdirectory(a)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE a::a)
我希望这可以解决您的问题。