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- зависимости между-мишеней-и-файлов-и-пользовательских-команд /