CMake: библиотека только для заголовков с созданными файлами

У меня есть библиотека, которая должна нести некоторые постоянные данные, введенные из содержимого не исходных файлов (в данном случае, код шейдера OpenGL). Для достижения этого я использую add_custom_command() генерировать включаемые файлы, которые я могу затем #include в мой код для инициализации константных статических переменных.

Это прекрасно работает с обычными библиотеками (статическими или общими), но теперь я хотел бы сделать мою библиотеку только заголовочной. Возможность 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()

3 ответа

Создание статической библиотеки с заголовками как единственными источниками работало для меня. Это, конечно, только обходной путь.

  • Создание статической библиотеки только с заголовочными файлами приводит к пустой библиотеке. Моя говорит !<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 генераторов.

Вы можете использовать target_sources в CMake 3.1, чтобы указывать потребителям компилировать файлы интерфейса:

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

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

Я столкнулся с сопоставимыми проблемами при попытке использовать рад: https://github.com/Dav1dde/glad

Он использует пользовательскую команду CMake для создания привязки, что означает, что файлы, которые нужно включить в проект, использующий "гладкие", не существуют, так что CMake не создает "рад" (которые будут создавать эти файлы)...

Я пока не пробовал, но пример 3 по следующей ссылке кажется хорошим решением, и я считаю, что он может работать в вашем случае: https://samthursfield.wordpress.com/2015/11/21/cmake- зависимости между-мишеней-и-файлов-и-пользовательских-команд /

Другие вопросы по тегам