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

5
我有一个包含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”引用库,看起来很干净。但是,仍然需要指向原始的include目录以获取.h文件,这让我感觉好像还缺少了些什么。似乎cmake应该有一个干净的解决方案。

1
请注意:如果要强制使用C++11,还需要CXX_STANDARD_REQUIRED。如果需要,最好将其作为目标属性添加,以转发此要求... - Mizux
4个回答

4

我对CMake相当陌生,但我认为你想要的是“add_custom_command”。

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

可能会起作用。

这很好,但命令是copy而不是cp。参考:https://cmake.org/cmake/help/latest/manual/cmake.1.html#run-a-command-line-tool - Kingsley
@Kingsley - 已相应更改。谢谢。 - natersoz

3
你要找的是以下结构:`

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

您的 CMakeLists 文件将如下所示:

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

谢谢您提供的最后一部分内容!我相信那是对问题标题的回答,即使您为OP提出了更好的解决方案。 - Andreu Gimenez

1
作为CMake的通用规则,源代码应该放在源目录中,而二进制文件和其他生成的文件应该放在构建目录中。所以你的愿望不太符合CMake的规范。
当你安装项目时,CMake会根据你的愿望放置头文件和库文件。然后你可以指定将哪些内容复制到哪里。
由于你不想安装此模块,最好的方法是提供一个CMake配置文件来创建一个包。这意味着你的项目Foo会生成一个名为FooConfig.cmake的文件,其中包含包含和库的路径。其他的CMake项目将使用find_package(Foo)来查找该文件。通过添加对Foo_DIR的提示,你可以让CMake在非标准目录中找到你的项目。
进一步阅读:
请注意,configure_file与您所需的内容无关,这个令人困惑的名称有历史原因。您可以使用此命令,但本质上它是无关的。
更新:经过更新后,我认为您想要使用外部项目。它的行为类似于内部库,但相当分离。请参见https://cmake.org/cmake/help/latest/module/ExternalProject.html

谢谢,这很有帮助。我更新了原始帖子以澄清我认为我正在寻找的内容,而且它肯定应该是cmake-y的。我不仅仅是想要一个快速修复;这是为了让我更好地理解。 - Jim B.
@JimBaldwin,我已经相应地更新了我的答案。 - usr1234567

0

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

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

既然您不想安装规则,也不需要添加$<INSTALL_INTERFACE:include>...

顺便说一下,如果您是在源代码之外进行构建,则不必复制包含文件到构建目录中。

附注:如果您还要生成头文件,请简单地添加$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接