14

我有一个库,它需要携带一些从非源文件的内容(在本例中为 OpenGL 着色器代码)注入的常量数据。为了实现这一点,我使用add_custom_command()生成包含文件,然后我可以#include在我的代码中初始化 const 静态变量。

这与常规库(静态或共享)完美配合,但现在我想让我的库只包含标题。C++ 让静态方法返回静态数据而不冒在每个翻译单元中复制该数据的风险(“神奇静态”)的能力使这成为可能。

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

(我意识到我的库没有实际义务仅是标头。在这种特殊情况下,我想要这样做的原因是我希望正在执行 OpenGL 的库保持独立于任何特定的绑定库 [例如GLEWorGLee或 newcomer 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()
4

3 回答 3

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 生成器。

于 2017-07-01T23:08:49.167 回答
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

于 2015-02-10T00:26:33.443 回答
1

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

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

我还没有尝试过,但以下链接的示例 3 似乎是一个很好的解决方案,我相信它可能适用于您的情况: https ://samthursfield.wordpress.com/2015/11/21/cmake-目标和文件之间的依赖项和自定义命令/

于 2016-06-27T12:29:26.277 回答