Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
包含子库的现代CMake库_Cmake - Fatal编程技术网

包含子库的现代CMake库

包含子库的现代CMake库,cmake,Cmake,我有几个库(子项目)作为一个主库的一部分。如何在“主库”(a)中聚合子库(b) 目标是只拥有一个库a,并按如下方式使用子库#include (有没有一种方法可以让include路径如下:#include?) 假设文件夹结构如下: a |-- CMakeLists.txt |-- aConfig.cmake `-- b |-- CMakeLists.txt |-- include | `-- b | `-- b.h `-- src

我有几个库(子项目)作为一个主库的一部分。如何在“主库”(a)中聚合子库(b)

目标是只拥有一个库
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)