我有一个库既可以用作标题库,也可以用作传统库。要启用此可选标头功能,如果以仅标头模式编译,则库包含.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生成的makefile 总是编译.cpp
文件,即使启用了仅标题模式且目标为HEADER_ONLY_TARGET
。
如何阻止CMake生成的makefile以仅标题模式编译源文件?
请注意,依赖于CMake生成的输出的 IDE(例如Qt Creator)应该同时显示标题和源文件作为项目的一部分。
如果我不对任何源文件进行全局处理,而只对.hpp
头文件进行全局处理,则CMake会抱怨没有为库目标选择源文件,并且依赖于CMake文件的IDE将不会显示任何项目
答案 0 :(得分:4)
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)
另请参阅 Transitive Usage Requirements 以及有关创建包等的所有其他CMake手册。
定义所有库类型并让消费者在它们之间进行选择的方法概述如下:
Opt-in header-only libraries with 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)
答案 1 :(得分:4)
尝试设置源文件' HEADER_FILE_ONLY
属性以阻止它们构建,例如:
if (LIBRARY_HEADERONLY)
set_source_files_properties(${SRC_LIST} PROPERTIES HEADER_FILE_ONLY 1)
...
endif()
答案 2 :(得分:0)
为什么不将HEOBERS和SRC文件的GLOB分开?您可以添加一个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 libraries (header-only ones)的机会。