0

我有一个my-library/带有自定义目标的独立库,它通过外部命令生成一些标头。为了将包含这些标头的目录从父目录导出为消耗品,我想执行以下操作:

add_custom_target(my-target ALL
    COMMAND ...
)
target_include_directories(my-target
    INTERFACE my_include_directory/
)

并从父项目中使用它:

add_subdirectory(my-library)
add_executable(consumer ...)
add_dependencies(consumer my-target)

这在语义上对我my_include_directory/来说是正常的,并且对consumer. 然而,这会导致:

target_include_directories called with non-compliant target type

我能想出的最佳解决方案是将库中的包含目录作为变量导出:

add_custom_target(my-target ALL
    COMMAND ...
)
set(MY_TARGET_INCLUDE_DIRS my_include_directory/ PARENT_SCOPE)

并通过此变量使用包含目录:

add_subdirectory(my-library)
add_executable(consumer ...)
add_dependencies(consumer my-target)
target_include_directories(consumer PRIVATE ${MY_TARGET_INCLUDE_DIRS})

这并不理想。有更好的解决方案还是我看错了?

4

2 回答 2

2

如果您想使用主项目构建库,那么您可能希望将生成的标头公开为接口库。这样,消费目标就不会关心或知道生成了标头,而只是像往常一样使用target_link_libraries() 。您也可能不想使用add_custom_target()来生成标头。根据文档:

目标没有输出文件,总是被认为是过时的

这意味着在构建时将始终生成标头。而不是仅在输入更改时才构建。

下面是使用add_custom_command()生成标头并通过add_custom_target()连接到接口库的示例。

my_library/CMakeLists.txt

set(INPUT_FILE "${CMAKE_CURRENT_LIST_DIR}/header.in")
set(GENERATED_HEADER "${CMAKE_CURRENT_BINARY_DIR}/some_header.h")

add_custom_command(
    OUTPUT ${GENERATED_HEADER}
    COMMAND ${CMAKE_COMMAND} -E copy ${INPUT_FILE} ${GENERATED_HEADER}
    DEPENDS ${INPUT_FILE}
    )

# Per the docs for add_custom_command, we use a custom target depending
# on the generated header to ensure it is only generated at most once per
# build
add_custom_target(local_target DEPENDS ${GENERATED_HEADER})

add_library(my_library INTERFACE)
target_include_directories(my_library INTERFACE ${CMAKE_CURRENT_BINARY_DIR})

# Per docs for add_dependencies
#
#   Dependencies added to an imported target or an interface library are
#   followed transitively
# 
# This ensures that the `local_target` will be built prior to anything that may end
# up using `my_library`.
add_dependencies(my_library local_target)

my_library/header.in

#define SOME_DEFINE 4

./CMakeLists.txt

cmake_minimum_required(VERSION 3.15)

project(example)

add_subdirectory(my_library)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE my_library)

./main.cpp

#include <stdio.h>

#include "some_header.h"

int main(int argc, char *argv[]) {
    printf("The value is %d.\n", SOME_DEFINE);
}
于 2021-01-16T05:10:28.010 回答
0

假设您分发二进制文件,只需install为该目录添加一条指令,并确保通过INCLUDES DESTINATIONof列出您安装标头的目录install(TARGETS)

add_library(my-library ...)

add_custom_target(my-target ALL
    COMMAND ...
)

set(_INCLUDE_INSTALL_DIR my-library/includes)

add_dependencies(my-library my-target)
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated-includes/" DESTINATION ${_INCLUDE_INSTALL_DIR})
install(TARGETS my-library EXPORT my-library
    LIBRARY DESTINATION my-library/lib
    INCLUDES DESTINATION ${_INCLUDE_INSTALL_DIR})

install(EXPORT my-library DESTINATION my-library/lib/cmake FILE my-library-config.cmake)

这样,您应该获得一个配置脚本以与可用于find_package获取导入目标的 lib 一起部署my-library(假设已my-library安装的目录或其父目录位于CMAKE_PREFIX_PATH.

find_package(my-library REQUIRED)

add_executable(consumer ...)
target_link_libraries(consumer PRIVATE my-library)
于 2021-01-14T19:57:27.890 回答