使用CMAKE在一个项目中包括并访问多个.SO文件和标题
我有一个简单的foobar
项目,其目录布局如下:
.
├── CMakeLists.txt
└── src
├── CMakeLists.txt
├── Foo
│ ├── CMakeLists.txt
│ ├── foo.cpp
│ └── foo.h
└── Bar
├── CMakeLists.txt
├── bar.cpp
└── bar.h
其中foo
是独立的,但bar
取决于foo
>并且应该能够#include< foo/foo.h>
。
我的顶级cmakelists.txt
文件是:
# Specify cmake version
cmake_minimum_required(VERSION 3.10)
# Set the project name
project(foobar VERSION 0.1.0)
# Specify the C++ standard
set(CMAKE_CXX_COMPILER /usr/bin/g++)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -O3")
# Set location for .so files
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}")
# Set location for executables
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
# Add libraries
add_subdirectory(src)
# Install library
install(TARGETS Foo Bar LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
我的src
celve是:
add_subdirectory(Foo)
add_subdirectory(Bar)
我的foo
celver is:
add_library(Foo SHARED foo.cpp)
最后我的bar
级别是:
add_library(Bar SHARED bar.cpp)
add_dependencies(Bar Foo)
target_link_libraries(Bar Foo)
调用cmake
顺利进行,但是在make
上,我得到以下内容:
Scanning dependencies of target Foo
[ 25%] Building CXX object src/Foo/CMakeFiles/Foo.dir/foo.cpp.o
[ 50%] Linking CXX shared library libFoo.so
[ 50%] Built target Foo
Scanning dependencies of target Bar
[ 75%] Building CXX object src/Bar/CMakeFiles/Bar.dir/bar.cpp.o
In file included from /home/drjrm3/code/cmake_app/src/Bar/bar.cpp:1:
/home/drjrm3/code/cmake_app/src/Bar/bar.h:3:10: fatal error: Foo/foo.h: No such file or directory
3 | #include <Foo/foo.h>
| ^~~~~~~~~~~
compilation terminated.
make[2]: *** [src/Bar/CMakeFiles/Bar.dir/build.make:63: src/Bar/CMakeFiles/Bar.dir/bar.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:160: src/Bar/CMakeFiles/Bar.dir/all] Error 2
make: *** [Makefile:130: all] Error 2
这表明我没有正确地制作foo
可见bar
以我希望的方式。
需要更改的内容,以便每个人都可以将它们内置到孤立的共享对象库中,但是bar
取决于foo
和can &lt; foo/foo/foo.h&gt; 在该子组件中可以看到吗?
请注意,我制作这些共享对象的选择是因为这只是一个更大的项目的一个最小示例,在该项目中,我有多个组件和多个应用程序,但想为这个问题做一个最小的示例。实际上,我在 github 任何人都有兴趣。
I have a simple foobar
project which has a directory layout as follows:
.
├── CMakeLists.txt
└── src
├── CMakeLists.txt
├── Foo
│ ├── CMakeLists.txt
│ ├── foo.cpp
│ └── foo.h
└── Bar
├── CMakeLists.txt
├── bar.cpp
└── bar.h
Where Foo
is standalone but Bar
depends on Foo
and should be able to #include <Foo/foo.h>
.
My top level CMakeLists.txt
file is:
# Specify cmake version
cmake_minimum_required(VERSION 3.10)
# Set the project name
project(foobar VERSION 0.1.0)
# Specify the C++ standard
set(CMAKE_CXX_COMPILER /usr/bin/g++)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -O3")
# Set location for .so files
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}")
# Set location for executables
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
# Add libraries
add_subdirectory(src)
# Install library
install(TARGETS Foo Bar LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
my src
level is:
add_subdirectory(Foo)
add_subdirectory(Bar)
my Foo
level is:
add_library(Foo SHARED foo.cpp)
and finally my Bar
level is:
add_library(Bar SHARED bar.cpp)
add_dependencies(Bar Foo)
target_link_libraries(Bar Foo)
Invoking cmake
goes OK, but upon make
I get the following:
Scanning dependencies of target Foo
[ 25%] Building CXX object src/Foo/CMakeFiles/Foo.dir/foo.cpp.o
[ 50%] Linking CXX shared library libFoo.so
[ 50%] Built target Foo
Scanning dependencies of target Bar
[ 75%] Building CXX object src/Bar/CMakeFiles/Bar.dir/bar.cpp.o
In file included from /home/drjrm3/code/cmake_app/src/Bar/bar.cpp:1:
/home/drjrm3/code/cmake_app/src/Bar/bar.h:3:10: fatal error: Foo/foo.h: No such file or directory
3 | #include <Foo/foo.h>
| ^~~~~~~~~~~
compilation terminated.
make[2]: *** [src/Bar/CMakeFiles/Bar.dir/build.make:63: src/Bar/CMakeFiles/Bar.dir/bar.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:160: src/Bar/CMakeFiles/Bar.dir/all] Error 2
make: *** [Makefile:130: all] Error 2
which shows me that I am not properly making Foo
visible to Bar
in the way that I'm hoping to.
What needs to change so that these can each be built into isolated shared object libraries but Bar
depends upon Foo
and can <Foo/foo.h>
can be visible from within that subcomponent?
Note that my choices for making these shared objects is because this is just a minimal example of a bigger project where I have multiple components and multiple apps but wanted to make a minimal example for this question. In fact I have this example up on Github is anyone is interested.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这里的关键概念是属性可见性。 Cmake中有两种类型:
私有
:属性会影响正在构建的目标。接口
:该属性会直接或通过target_link_libraries(... interface ...)
直接或过渡地链接到的目标。public
可见性只是两个 的速记。所以。酒吧的构建应该看起来像:
我们在此处使用
public
可见性,因为酒吧的标题包括foo的标头。也就是说,链接到Bar的库也需要了解FOO。现在,我们像这样构建foo:
魔术的主要位是
$&lt; build_interface:...&gt;
Generator Expression。这样可以防止当您最终使用install(导出)
创建find_package
-compatible cmake时,可以防止包含目录(这是通往构建计算机某个地方的绝对路径)。这些库的包装。否则,我们只是依靠
$ {cmake_current_source_dir}/..
将从foo
bar (以及任何东西)传播。链接到bar
),因为此路径位于接口
foo
的接口中。The key concept here is property visibility. There are two types in CMake:
PRIVATE
: the property affects the target being built.INTERFACE
: the property affects targets that link to this one directly, or transitively throughtarget_link_libraries(... INTERFACE ...)
.The
PUBLIC
visibility is simply a shorthand for both.Therefore. the build for Bar should look like so:
We use
PUBLIC
visibility here because Bar's headers include Foo's headers. That is, libraries linking to Bar need to know about Foo as well.Now we build Foo like so:
The main bit of magic here is the
$<BUILD_INTERFACE:...>
generator expression. This prevents the include directory (which is an absolute path to somewhere on your build machine) from being exported when you eventually useinstall(EXPORT)
to create afind_package
-compatible CMake package for these libraries.Otherwise, we're just relying on the fact that
${CMAKE_CURRENT_SOURCE_DIR}/..
will be propagated fromFoo
toBar
(and anything that links toBar
) because this path is in theINTERFACE
ofFoo
.