CMake:将头文件复制到输出目录

CMake: copy header file to output directory

本文关键字:输出 复制 文件 CMake      更新时间:2023-10-16

我有一个包含 c++ 源文件和头文件的目录。 我想创建一个 CMakeLists.txt将其构建为一个库,以便在将其作为子目录包含的其他 CMake 项目中使用。

结构:

example/
foo.h
foo.cpp
CMakeLists.txt

我遇到的问题是 CMake 似乎没有将 foo.h 放在任何地方,因此让父 CMake 知道如何找到头文件让我感到困惑。

这是我目前的CMakeLists.txt:

cmake_minimum_required(VERSION 3.8.2)
project(example)
set (CMAKE_CXX_STANDARD 11)
# add library target foo
add_library(foo STATIC foo.cpp)
# tell cmake where to find headers for it
target_include_directories(foo PUBLIC .)
# sad attempt to get it to output the header
set_target_properties(foo PROPERTIES PUBLIC_HEADER foo.h)

我不想安装。 这里的想法是,该库将由其他 CMake 项目使用,而不是由整个系统使用。

理想情况下,foo.h 将显示在构建目录中的 libfoo.a 旁边。

我试过称它为"框架",没有运气;这只能是一个macOS框架。

我相信我可以陪审团操纵这个,但我认为有一个最佳实践。

对"这里有更好的方法"的答案也持开放态度......

更新

这可能有助于澄清我认为我想如何将这个项目拉到另一个项目中。 我看到其他项目使用这样的东西:

add_subdirectory(<path_to_foo>/foo foo_build)

这会导致 foo 构建发生在子目录中。 这允许我使用"foo_build"来引用库,这很好而且很干净。 但是,我仍然必须指向原始的包含目录才能获取.h文件,这让我觉得我错过了一些东西。

似乎cmake会为此提供一个干净的解决方案。

我对CMake相当陌生,但我认为你想要的是一个"add_custom_command"。

add_custom_command(TARGET foo.a POST_BUILD COMMAND copy foo.h ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})

这也许可行。

您要查找的是以下结构:

example/
- CMakeLists.txt
- src/
- main.c
- sub/
- foo/
- CMakeLists.txt
- src/
- foo/
- foo.c
- foo.h

您的 CMakeList 将如下所示

example/CMakeLists.txt

# use modern target-based cmake features
cmake_minimum_required (VERSION 3.0)
# projectname
project (ff1_selfcheck)
add_subdirectory (sub/foo)
# executable to create
add_executable(${PROJECT_NAME}
src/main.c
)
# link libraries
target_link_libraries(${PROJECT_NAME}
PRIVATE
foo # imported target
)

example/sub/foo/CMakeLists.txt

# use modern target-based cmake features
cmake_minimum_required (VERSION 3.0)
# projectname
project (foo)
# executable to create
add_library(${PROJECT_NAME}
src/foo.c
)
# directories where to search for header files
target_include_directories(${PROJECT_NAME}
PUBLIC
source # the headerfiles in source are the includes
)

通过使用target_link_libraries(...)中的项目名称foo,您可以引用 foo 库目标

此外,通过在 foo 库中使用PUBLIC关键字,您的标头(您的包含目录)会自动传播到通过add_subdirectory(...)添加此库的每个 CMake 项目。

因此,您无需复制标题!CMake>= 2.8.12 很漂亮,不是吗?


如果您确实想通过 CMake 复制文件,请执行以下操作:

file(COPY srcDir
DESTINATION dstDir
FILES_MATCHING
PATTERN "*.h"
)

看看这里: https://cmake.org/cmake/help/latest/command/file.html#copy

作为 CMake 的一般规则,源代码保存在源目录中,二进制文件和其他生成的文件保存在构建目录中。所以你希望不是很CMake。
CMake 会在您安装项目时根据您的意愿放置标头和库。然后,您可以指定要复制到何处的内容。

由于你不想安装此模块,因此最好的方法是通过为项目提供 CMake 配置文件来创建包。这意味着您的项目Foo将生成一个文件FooConfig.cmake其中包含包含和库的路径。另一个 CMake 项目将使用find_package(Foo)来查找文件。通过向Foo_DIR添加提示,可以使 CMake 在非标准目录中查找项目。

延伸阅读:

  • 有关包的 CMake 文档
  • 关于如何使用库

请注意,configure_file与您想要的无关,令人困惑的名称具有历史原因。您可以使用此命令,但本身是无关的。

更新:更新后,我认为您想使用外部项目。行为类似于内部库,但非常分离。见 https://cmake.org/cmake/help/latest/module/ExternalProject.html

你应该对你的"foo"包含目录使用生成器表达式:

target_include_directories(foo PUBLIC 
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR})

而且由于您不想要安装规则,因此不需要也添加$<INSTALL_INTERFACE:include>...

顺便说一句,您应该不在乎将包含文件复制到构建目录中(假设您正在从源代码中构建)。

PS:如果您还生成头文件,只需添加$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>