将两个 cmake 项目并排链接

Link two cmake projects next to each other

提问人:Divelix 提问时间:11/16/2023 最后编辑:Divelix 更新时间:11/20/2023 访问量:82

问:

假设我有两个 cmake 库: 和 ,其中取决于 。我怎么能不把它们放到一个通用的cmake项目中,这意味着应该只有两个CMakeLists.txt(一个用于lib1,一个用于lib2),而不是将它们链接在一起的通用CMakeLists.txt。lib1lib2lib2lib1

cmake_agnostic_root/
|-- lib1/
|   |-- src/
|   |-- include/
|   |-- CMakeLists.txt
|-- lib2/
|   |-- src/
|   |-- include/
|   |-- CMakeLists.txt
|-- (there must be no CMakeLists.txt on this level)

在我的理解中,CMakeLists.txt 中应该只有一些东西会包含 .lib2lib1

我尝试了什么(没有任何效果):

  1. add_subdirectory: 尝试将这一行添加到 cmake:lib2
add_subdirectory(../lib1 lib1)

但仍然找不到 的标题lib2lib1

  1. 外部项目: 尝试将以下行添加到cmake:lib2
include(ExternalProject)

ExternalProject_Add(
  lib1
  SOURCE_DIR ../lib1
)

可能我错误地使用此命令,因为在所有示例中它都会下载 git 存储库,但我需要在 旁边使用本地文件夹。lib1lib2

我做错了什么?

编辑:我想调用cmake触发构建,然后用它来构建。lib2lib1lib2

C++ CMake

评论

0赞 pptaszni 11/16/2023
不是,而是,.这将起作用(解释为什么它不适合你),但这不是一个好的做法。如果你真的不想有任何可以构建 lib1 的根 CMakeLists.txt,然后在 lib2 中使用该依赖项,那么你需要打包你的 lib1,安装它,然后找到它,如果你不想要它,可能在 中带有提示。add_subdirectory(../lib1 lib1)add_subdirectory(../lib1)find_packageCMAKE_MODULE_PATH
0赞 Divelix 11/16/2023
@pptaszni如果我按照你的方式add_subdirectory,我会收到错误:add_subdirectory not given a binary directory but the given source directory lib1 is not a subdirectory of lib2. When specifying an out-of-tree source a binary directory must be explicitly specified.
0赞 pptaszni 11/16/2023
嗯,好吧,因为它不在你的源代码树中。然后 - 第二个参数是 lib1 的构建树。但同样,不要这样做。add_subdirectory(../lib1 ../lib1/build)
0赞 Friedrich 11/16/2023
如果您想要两个相互依赖的目标,最简单的方法是将它们放在一个 CMake 项目中。FWIW,我一直在做一些项目,其中“父级”基本上包含一些行(加上一些 CMake 绒毛)是由脚本创建的。CMakeLists.txtadd_subdirectory
0赞 Divelix 11/16/2023
@pptaszni这也行不通。无论如何,谢谢你的帮助。我 root 与 cmake 无关的重点是因为实际上我的 lib2 是使用 catkin(基于 cmake 的构建系统)构建的 ROS1 包,而应该有另一个 lib3 也使用 lib1,但使用 colcon(另一个基于 cmake 的构建系统,但用于 ROS2)。

答:

0赞 Divelix 11/16/2023 #1

我在 KISS-ICP 中找到了答案。CMakeLists.txt中应该有这样的函数调用。不知道它有什么作用,但有它的内容:set_global_target_propertieslib1

function(set_global_target_properties target)
  target_compile_features(${target} PUBLIC cxx_std_17)
  target_compile_definitions(${target} PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,MSVC>:_USE_MATH_DEFINES>)
  target_compile_options(
    ${target}
    PRIVATE # MSVC
            $<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/W4>
            $<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/WX>
            # Clang/AppleClang
            $<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-fcolor-diagnostics>
            $<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Werror>
            $<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Wall>
            $<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Wextra>
            $<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Wconversion>
            $<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Wno-sign-conversion>
            # GNU
            $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-fdiagnostics-color=always>
            $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Werror>
            $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wall>
            $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wextra>
            $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-pedantic>
            $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wcast-align>
            $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wcast-qual>
            $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wconversion>
            $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wdisabled-optimization>
            $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Woverloaded-virtual>)
  set(INCLUDE_DIRS ${PROJECT_SOURCE_DIR})
  get_filename_component(INCLUDE_DIRS ${INCLUDE_DIRS} PATH)
  target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
                             PUBLIC $<BUILD_INTERFACE:${INCLUDE_DIRS}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
endfunction()
1赞 Sergey Vlasov 11/17/2023 #2

我用exe + lib创建了一个测试项目:

cmake_agnostic_root/
|-- app/
|   |-- src/
|   |-- include/
|   |-- CMakeLists.txt
|-- lib/
|   |-- src/
|   |-- include/
|   |-- CMakeLists.txt
|-- (there must be no CMakeLists.txt on this level)

它没有一点丑陋,需要改进,但是一个很好的起点

The exe CMakeList.txt:

project(app)

cmake_minimum_required(VERSION 3.16)

include(ExternalProject)

if (CMAKE_CONFIGURATION_TYPES)
    # support multiple configurations: Debug and Release 
    set(TEST_INSTALL_PREFIX "<INSTALL_DIR>/$<CONFIG>")
    set(TEST_LIBRARY_FILE ${CMAKE_BINARY_DIR}/test/$<CONFIG>/lib/test.lib)
    set(TEST_LIBRARY_HEADERS ${CMAKE_BINARY_DIR}/test/$<CONFIG>/include)
else()
    # single configuration: Debug or Release
    set(TEST_INSTALL_PREFIX "<INSTALL_DIR>")
    set(TEST_LIBRARY_FILE ${CMAKE_BINARY_DIR}/test/lib/libtest.a)
    set(TEST_LIBRARY_HEADERS ${CMAKE_BINARY_DIR}/test/include)
endif()

ExternalProject_Add(test.proj
    URL ${CMAKE_CURRENT_SOURCE_DIR}/../lib
    PREFIX test
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${TEST_INSTALL_PREFIX}
    BUILD_BYPRODUCTS ${TEST_LIBRARY_FILE}
)

add_library(test INTERFACE)
target_include_directories(test INTERFACE ${TEST_LIBRARY_HEADERS})
target_link_libraries(test INTERFACE ${TEST_LIBRARY_FILE})
add_dependencies(test test.proj)

add_executable(app src/main.cpp)
target_link_libraries(app test)

库的 CMakeList.txt:

project(test)

cmake_minimum_required(VERSION 3.16)

add_library(test src/test.cpp)
target_include_directories(test PRIVATE include)

install(TARGETS test DESTINATION lib)
install(FILES include/test.h DESTINATION include)

评论

0赞 Divelix 11/19/2023
我试图遵循您的答案并且命令运行没有错误,但是当我尝试使用内部构建文件夹创建可执行文件时,它会抛出:cmakemakemake[2]: *** No rule to make target 'test//lib/test.lib', needed by 'app'. Stop. make[1]: *** [CMakeFiles/Makefile2:111: CMakeFiles/app.dir/all] Error 2
0赞 Sergey Vlasov 11/19/2023
我使用了具有 2 种构建配置的 Visual Studio cmake 生成器:调试和发布。在您的情况下,可能没有必要使用 $<CONFIG>
0赞 Sergey Vlasov 11/19/2023
另外,尝试将“BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/test/$<CONFIG>/lib/test.lib”添加到ExternalProject_Add中。它指定 test.lib 必须由“test.proj”规则构建。
1赞 Sergey Vlasov 11/19/2023
问题也可能出在库名称上:Windows:test.lib,Linux:libtest.a
1赞 Sergey Vlasov 11/20/2023
我更新了我的示例以使用 Linux 和 Windows (MSVC)。对于 MSVC(Visual Studio cmake 生成器),支持多个生成配置。$<CONFIG> - 只是当前构建配置(调试或发布)的别名