3

我有一个既可以用作仅标头库也可以用作传统库的库。要启用此仅可选标头功能,.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)应将头文件和源文件都显示为项目的一部分。

如果我没有 glob 任何源文件,而只有.hpp头文件,CMake 将抱怨没有为库目标选择源文件,并且依赖于 CMake 文件的 IDE 将不会显示任何项目。

4

3 回答 3

5

尝试设置源文件的HEADER_FILE_ONLY属性以防止它们构建,例如:

if (LIBRARY_HEADERONLY)
    set_source_files_properties(${SRC_LIST} PROPERTIES HEADER_FILE_ONLY 1)
    ...
endif()

另请参阅文档

于 2015-01-16T15:58:40.333 回答
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)

另请参阅传递性使用要求和所有其他有关创建包等的 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)
于 2015-01-09T19:12:40.003 回答
0

为什么不将 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.XX 让您有机会创建INTERFACE 库(仅头文件)

于 2015-01-10T09:44:49.407 回答