У меня есть библиотека, которую можно использовать как библиотеку только для заголовков и как традиционную библиотеку. Чтобы включить эту необязательную функцию только для заголовка, библиотека включает .cpp
исходные файлы, если они скомпилированы в режиме только заголовка. Пример:
// Vector.hpp
// (Module file), intended to be included manually by the user
#ifndef LIBRARY_MODULE_VECTOR
#define LIBRARY_MODULE_VECTOR
#include "Library/Vector/Inc/Vector2.hpp"#include "Library/Vector/Inc/Vector3.hpp"#include "Library/Vector/Inc/VectorUtils.hpp"
#if defined(LIBRARY_HEADERONLY)
#include "Library/Vector/Src/Vector2.cpp"#include "Library/Vector/Src/Vector3.cpp"#include "Library/Vector/Src/VectorUtils.cpp"#endif
#endif
Когда пользователь включает Vector.hpp
в одном из его / ее проектов, если LIBRARY_HEADERONLY
определяется, исходные файлы реализации будут включены сразу после заголовочных файлов. Осторожное использование inline
Ключевое слово применяется, чтобы избежать нескольких определений.
Если LIBRARY_HEADERONLY
не определено, .cpp
файлы будут скомпилированы и библиотека должна быть связана.
Моя система сборки выбора CMake.
Используя флаг CMake, пользователь может определить или отменить определение LIBRARY_HEADERONLY
,
CMakeLists.txt
Файл похож на это:
# (not shown) set flag and cache variables...
# Include library directory
include_directories("./${INCLUDE_DIRECTORY}")
# Glob all library header/source files
file(GLOB_RECURSE SRC_LIST "${INC_DIR}/*" "${SRC_DIR}/*")
# (Not shown) Check if header-only mode is enabled
# (from now on we assume header-only mode is enabled and that
# LIBRARY_HEADERONLY is defined)
# Use all source/header files as a library target
add_library(HEADER_ONLY_TARGET STATIC ${SRC_LIST})
set_target_properties(HEADER_ONLY_TARGET PROPERTIES LINKER_LANGUAGE CXX)
install(DIRECTORY ${INC_DIR} DESTINATION .)
К сожалению, созданный CMake make-файл всегда компилирует .cpp
файлы, даже если включен режим только заголовка и цель HEADER_ONLY_TARGET
,
Как я могу помешать сгенерированному CMake make-файлу компилировать исходные файлы в режиме только заголовка?
Обратите внимание, что Среды IDE, зависящие от сгенерированного CMake вывода, такого как Qt Creator, должны отображать как заголовочные, так и исходные файлы как часть проекта.
Если я не потерю какой-либо исходный файл, а только .hpp
Заголовочные файлы, CMake будет жаловаться на то, что исходные файлы не были выбраны для цели библиотеки, а в средах разработки, использующих файлы CMake, не будет отображаться никакой элемент.
Попробуйте установить исходные файлы HEADER_FILE_ONLY
свойство препятствовать их строительству, например:
if (LIBRARY_HEADERONLY)
set_source_files_properties(${SRC_LIST} PROPERTIES HEADER_FILE_ONLY 1)
...
endif()
Также см. документация.
if (Create_Header_Only)
add_library(TargetName INTERFACE)
# Clients will build with -DLIBRARY_HEADERONLY
target_compile_definitions(TargetName INTERFACE LIBRARY_HEADERONLY)
else()
add_library(TargetName STATIC thesource.cpp)
endif()
# Clients will build with -Iinclude
target_include_directories(TargetName INTERFACE include)
Код клиента просто делает:
add_executable(mine main.cpp)
target_link_libraries(mine TargetName)
Смотрите также Требования к транзитивному использованию и все остальные руководства CMake по созданию пакетов и т. д.
Подход к определению всех типов библиотек и предоставлению возможности выбора между ними представлен в:
Отключить только заголовочные библиотеки с CMake
Что-то вроде:
add_library(lib_shared SHARED ...)
add_library(lib_shared STATIC ...)
add_library(lib_iface INTERFACE)
Так что потребитель делает выбор, на который ссылаться:
# target_link_libraries(consumer lib_static)
# target_link_libraries(consumer lib_shared)
target_link_libraries(consumer lib_iface)
Почему вы не отделяете файлы GLOB для HEADERS и SRC? Вы можете добавить dummy.cpp (пустой файл .cpp) для создания библиотек только для заголовков. Я имею в виду:
# Glob all library header files
file(GLOB_RECURSE HEADER_ONLY_LIST "${INC_DIR}/*.hpp")
# Glob all library src files
file(GLOB_RECURSE SRC_ONLY_LIST "${SRC_DIR}/*.cpp")
# Check if LIBRARY_HEADERONLY is defined, so you can filter the target files
if(LIBRARY_HEADERONLY)
set(SRC_LIST ${HEADER_ONLY_LIST} dummy.cpp) # I don't know if it's needed to add a dummy.cpp file with your set_target_properties(HEADER_ONLY_TARGET ...)
else()
set(SRC_LIST ${HEADER_ONLY_LIST} ${SRC_ONLY_LIST})
endif(LIBRARY_HEADERONLY)
# Use all source/header files as a library target
add_library(HEADER_ONLY_TARGET STATIC ${SRC_LIST})
set_target_properties(HEADER_ONLY_TARGET PROPERTIES LINKER_LANGUAGE CXX)
install(DIRECTORY ${INC_DIR} DESTINATION .)
В любом случае, CMake 3.X.X дает вам возможность создавать Библиотеки INTERFACE (только для заголовков).