c++ 如何在独立的CMake子目录中定义静态库,这些子目录依赖于彼此的接口和生成的头文件?

cyej8jka  于 2022-11-27  发布在  其他
关注(0)|答案(1)|浏览(140)

假设我有一个项目创建了两个静态库目标(foobar),它们之间有一个循环依赖关系。CMake明确允许这样做,并且它通常工作得很好,因为构建这些库的顺序并不重要。
但是,如果这两个库都生成头文件(Foo.hpp用于fooBar.hpp用于bar),则可能出现问题,因为头的生成通常作为构建库的一部分来完成也就是说,构建foo将生成Foo.hpp,但是还需要由bar构建的Bar.hppbar需要Foo.hpp ...
我找到了一个解决这个问题的方法,乍一看,似乎很完美。它包括使用add_custom_command生成头文件,然后使用target_sources将头文件添加到目标的PUBLIC源文件中。这样,目标本身及其依赖项都将对头文件有一个文件级依赖关系,从而在正确的时间触发自定义命令。
以下是我的解决方案的MWE:

cmake_minimum_required(VERSION 3.5)
project(Foo)

add_custom_command(
    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Foo.hpp
    COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/Foo.hpp
    COMMENT "Generating Foo.hpp"
)

add_library(foo STATIC Foo.cpp)
target_include_directories(foo PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_sources(foo PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/Foo.hpp)
target_link_libraries(foo bar)

add_custom_command(
    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Bar.hpp
    COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/Bar.hpp
    COMMENT "Generating Bar.hpp"
)

add_library(bar STATIC Bar.cpp)
target_include_directories(bar PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_sources(bar PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/Bar.hpp)
target_link_libraries(bar foo)

问题是自定义命令只有在从同一个目录(即documented)引用它们的输出时才能工作。如果我将项目拆分,并将foobar放在不同的目录中,则上面的解决方案不再工作。
所以我的问题是:是否有更好的方法来处理静态库生成的头文件之间的循环依赖关系?

mwg9r5ms

mwg9r5ms1#

如果我拆分我的项目并将foo和bar放在不同的目录中,上面的解决方案就不再起作用了。
您可以将目标的源文件放在专用的子目录中,并且仍然在同一个CMake“子目录”中定义它们的目标。

cmake_minimum_required(VERSION 3.5)
project(Foo)

add_custom_command(
    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Foo/Foo.hpp"
    COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/Foo/Foo.hpp"
    COMMENT "Generating Foo.hpp"
    VERBATIM
)

add_library(foo STATIC Foo/Foo.cpp)
target_include_directories(foo PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_sources(foo PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/Foo/Foo.hpp)
target_link_libraries(foo bar)

add_custom_command(
    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Bar/Bar.hpp"
    COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/Bar/Bar.hpp"
    COMMENT "Generating Bar.hpp"
    VERBATIM
)

add_library(bar STATIC Bar/Bar.cpp)
target_include_directories(bar PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_sources(bar PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/Bar/Bar.hpp)
target_link_libraries(bar foo)

如果您的意思是要在这些专用子目录中定义目标,您不能只执行以下操作:

# :/CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(Foo)
add_subdirectory(Foo)
add_subdirectory(Bar)

# :/Foo/CMakeLists.txt
add_custom_command(
    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Foo/Foo.hpp"
    COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/Foo/Foo.hpp"
    COMMENT "Generating Foo.hpp"
    VERBATIM
)
add_library(foo STATIC Foo.cpp)
target_include_directories(foo PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_sources(foo PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/Foo/Foo.hpp)
target_link_libraries(foo bar)

# :/Bar/CMakeLists.txt
add_custom_command(
    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Bar/Bar.hpp"
    COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/Bar/Bar.hpp"
    COMMENT "Generating Bar.hpp"
    VERBATIM
)
add_library(bar STATIC Bar.cpp)
target_include_directories(bar PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_sources(bar PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/Bar/Bar.hpp)
target_link_libraries(bar foo)

相关问题