在仅标头模式下编译源文件时,防止CMake生成的可选标头库的makefile

时间:2015-01-09 18:14:25

标签: c++ makefile cmake header-files 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

当用户在他/她的某个项目中包含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将不会显示任何项目

3 个答案:

答案 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()

另见documentation

答案 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)的机会。