阻止 optional-header-only 库的 CMake-generated makefile 在 header-only 模式下编译源文件
Preventing CMake-generated makefile for optional-header-only library from compiling source files in header-only mode
我有一个图书馆,既可以用作 header-only 图书馆,也可以用作传统图书馆。要启用此可选的 header-only 功能,如果在 header-only 模式下编译,库将包含 .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
当用户在 his/her 项目之一中包含 Vector.hpp
时,如果定义了 LIBRARY_HEADERONLY
,则将在 header 文件之后立即包含实现源文件。小心使用 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-generated makefile 总是 编译 .cpp
文件,即使启用 header-only 模式并且目标是 HEADER_ONLY_TARGET
.
如何防止 CMake-generated makefile 在 header-only 模式下编译源文件?
请注意,依赖于 CMake-generated 输出的 IDE,例如 Qt Creator,应该将 header 和源文件 作为项目的一部分显示。
如果我不通配任何源文件,而只通配 .hpp
header 文件,CMake 会抱怨没有为库目标和依赖 CMake 的 IDE 选择源文件文件将不会显示任何项目。
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)
以便消费者选择 link 到:
# target_link_libraries(consumer lib_static)
# target_link_libraries(consumer lib_shared)
target_link_libraries(consumer lib_iface)
为什么不将 HEADERS 和 SRC 文件的 GLOB 分开?您可以添加一个 dummy.cpp(一个空的 .cpp 文件)来创建 header-only 库。我的意思是:
# 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).
的机会
尝试设置源文件的 HEADER_FILE_ONLY
属性 以防止构建它们,例如:
if (LIBRARY_HEADERONLY)
set_source_files_properties(${SRC_LIST} PROPERTIES HEADER_FILE_ONLY 1)
...
endif()
另见 documentation。
我有一个图书馆,既可以用作 header-only 图书馆,也可以用作传统图书馆。要启用此可选的 header-only 功能,如果在 header-only 模式下编译,库将包含 .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
当用户在 his/her 项目之一中包含 Vector.hpp
时,如果定义了 LIBRARY_HEADERONLY
,则将在 header 文件之后立即包含实现源文件。小心使用 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-generated makefile 总是 编译 .cpp
文件,即使启用 header-only 模式并且目标是 HEADER_ONLY_TARGET
.
如何防止 CMake-generated makefile 在 header-only 模式下编译源文件?
请注意,依赖于 CMake-generated 输出的 IDE,例如 Qt Creator,应该将 header 和源文件 作为项目的一部分显示。
如果我不通配任何源文件,而只通配 .hpp
header 文件,CMake 会抱怨没有为库目标和依赖 CMake 的 IDE 选择源文件文件将不会显示任何项目。
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)
以便消费者选择 link 到:
# target_link_libraries(consumer lib_static)
# target_link_libraries(consumer lib_shared)
target_link_libraries(consumer lib_iface)
为什么不将 HEADERS 和 SRC 文件的 GLOB 分开?您可以添加一个 dummy.cpp(一个空的 .cpp 文件)来创建 header-only 库。我的意思是:
# 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).
的机会尝试设置源文件的 HEADER_FILE_ONLY
属性 以防止构建它们,例如:
if (LIBRARY_HEADERONLY)
set_source_files_properties(${SRC_LIST} PROPERTIES HEADER_FILE_ONLY 1)
...
endif()
另见 documentation。