CMake:带有生成文件的仅标头库

问题描述 投票:0回答:4

我有一个库,需要携带一些从非源文件内容注入的常量数据(在本例中为 OpenGL 着色器代码)。为了实现这一目标,我使用

add_custom_command()
生成包含文件,然后可以将其
#include
放入我的代码中以初始化 const 静态变量。

这与常规库(静态或共享)完美配合,但现在我想让我的库仅包含头文件。 C++ 允许静态方法返回静态数据,而无需冒在每个翻译单元中重复该数据的风险(“神奇的静态”),这使得这成为可能。

然而,问题是 CMake 似乎假设 INTERFACE 库(这是我用来创建仅标头库的 CMake 功能)不需要构建 - 在这种情况下,这是错误的。

(我意识到我的库没有实际义务仅包含头文件。在这种特殊情况下,我想要这样做的原因是我希望正在执行 OpenGL 的库保持独立于任何特定的绑定库[例如

GLEW
GLee
或新人
glbinding
]。通过仅保留我的库标头,我可以将该选择留给用户 - 他所需要做的就是
#include
绑定库的标头。在我之前。)

有人知道有一种方法可以让 CMake 最迟在构建消费者项目时触发标头生成自定义命令吗?

编辑:我刚刚意识到,通过保持我的库静态,但仍然保留我的所有代码除了头文件中的常量数据,我可以拥有“两全其美”。这样,仍然不需要选择特定的 OpenGL 绑定库。 然而,让一个库仅包含头文件仍然有一些优点 - 使用简单 - 所以我将我的问题悬而未决。

编辑 #2:这是我的

CMakeLists.txt
文件的相关部分(我只从末尾剥离了库依赖项 - 所有标头):

set(SHADER_FILES "src/vertex.glsl" "src/fragment.glsl")

add_library(libGPCGUIGLRenderer INTERFACE)
target_sources(libGPCGUIGLRenderer INTERFACE ${SHADER_FILES})

target_include_directories(libGPCGUIGLRenderer BEFORE
  INTERFACE
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

# Embed shader files

source_group("Shader files" FILES ${SHADER_FILES})

set(GENERATED "${CMAKE_CURRENT_BINARY_DIR}/generated")
target_include_directories(libGPCGUIGLRenderer INTERFACE ${GENERATED})

# Find the GPC Bin2C utility
find_package(GPCBin2C REQUIRED)

# Add a custom target and a dependency for each shader file    
foreach(shader ${SHADER_FILES})
  get_filename_component(name "${shader}" NAME)
  set(shader_header "${GENERATED}/${name}.h")
  add_custom_command(
    OUTPUT ${shader_header}
    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${shader}
    COMMAND GPCBin2C --input=${CMAKE_CURRENT_SOURCE_DIR}/${shader} --output=${shader_header}
  )
  target_sources(libGPCGUIGLRenderer INTERFACE ${shader_header})
endforeach()
cmake header-only
4个回答
8
投票

创建一个以标头作为唯一来源的静态库对我有用。当然,这只是一种解决方法。

  • 创建仅包含头文件的静态库会导致库为空。我的只有
    !<arch>
    内容。
  • CMake 将自动获取子目录之间正确的依赖关系。
  • 由于所有源都是标头,因此您需要告诉 CMake 应使用哪种链接器语言。

代码:

set(OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/generated_include")
add_custom_command(
    OUTPUT "${OUTDIR}/outfile.h"
    # Replace the next two lines with a proper generating script.
    COMMAND mkdir -p ${OUTDIR}
    COMMAND touch ${OUTDIR}/outfile.h
)

# Note, I am only adding header files to the library.
add_library(generated-headers STATIC 
    "${OUTDIR}/outfile.h"
)
set_target_properties(generated-headers
    PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(generated-headers PUBLIC ${OUTDIR})

在其他目录中使用,如下所示:

# In any other directory of the same CMake project:
add_executable(main main.cpp)
target_link_libraries(main generated-headers)

在 CMake 3.2、3.8 和 3.9 上测试。使用 Ninja 和 Make 生成器。


3
投票

可以使用CMake 3.1中的target_sources来告诉消费者编译接口文件:

add_library(source_only INTERFACE)
target_sources(source_only INTERFACE foo.cpp) 

http://www.cmake.org/cmake/help/v3.1/command/target_sources.html


1
投票

我在尝试使用glad时遇到了类似的问题:https://github.com/Dav1dde/glad

它使用自定义 CMake 命令来构建绑定,这意味着您需要包含在使用glad的项目中的文件不存在,因此CMake不会构建glad(这将创建这些文件)...

我还没有尝试过,但以下链接的示例 3 似乎是一个很好的解决方案,我相信它可能适合您的情况: https://samthursfield.wordpress.com/2015/11/21/cmake-dependency- Between-targets-and-files-and-custom-commands/


0
投票

你应该使用这个:

set_source_files_properties(your_generated.h PROPERTIES LANGUAGE CXX)

但请注意,这可能在不同的生成器上仍然会失败 - Xcode 不喜欢这样。但我尝试过的所有其他发电机都工作正常。

https://cmake.org/cmake/help/latest/prop_sf/LANGUAGE.html

© www.soinside.com 2019 - 2024. All rights reserved.