c++makefilecmakeheader-filesheader-only

Preventing CMake-generated makefile for optional-header-only library from compiling source files in header-only mode


I have a library that can both be used as an header-only library and as a traditional library. To enable this optional-header-only functionality, the library includes .cpp source files if compiled in header-only mode. Example:

// 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

When the user includes Vector.hpp in one of his/her projects, if LIBRARY_HEADERONLY is defined, the implementation source files will be included right after the header files. Careful usage of the inline keyword is applied to avoid multiple definitions.

If LIBRARY_HEADERONLY is undefined, the .cpp files will be compiled and the library will have to be linked.


My build system of choice is CMake.

Using a CMake flag, the user can define or undefine LIBRARY_HEADERONLY.

The CMakeLists.txt file is similar to this:

# (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 .)

Unfortunately, the CMake-generated makefile always compiles the .cpp files, even when header-only mode is enabled and the target is HEADER_ONLY_TARGET.

How can I prevent the CMake-generated makefile from compiling the source files in header-only mode?

Note that IDEs reliant on CMake-generated output, such as Qt Creator, should display both the header and source files as part of the project.

If I don't glob any source file, but only the .hpp header files, CMake will complain that no source files were selected for a library target, and IDEs that rely on CMake files will not display any item.


Solution

  • Try setting the source files' HEADER_FILE_ONLY property to prevent them from building, e.g.:

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

    Also see the documentation.