Solution #1 (configure + install)
Include config.hpp
file in your header file(i.e. foo.hpp
):
#ifndef FOO_HPP_
#define FOO_HPP_
#include "config.hpp" // FOO_DEBUG
class Foo {
public:
int result() const;
private:
int a_;
#ifdef FOO_DEBUG
int b_;
#endif // FOO_DEBUG
};
#endif // FOO_HPP_
config.hpp
is output of configure_file command:
configure_file(config.hpp.in "${PROJECT_BINARY_DIR}/config/config.hpp")
include_directories("${PROJECT_BINARY_DIR}/config")
install(FILES Foo.hpp "${PROJECT_BINARY_DIR}/config/config.hpp" DESTINATION include)
input file config.hpp.in
use special cmakedefine
directive:
#ifndef CONFIG_HPP_
#define CONFIG_HPP_
#cmakedefine FOO_DEBUG
#endif // CONFIG_HPP_
Note that when you use installed library in other project:
- you still need to specify include directories for library
- if your library have dependencies you need to link them manually
- you can't have 2 config files (Debug/Release)
Solution #2 (export/import target, recommended)
install(EXPORT ...) command can hold all information about using library
(aka usage requirements: including definitions, linked library, configuration etc):
add_library(Foo Foo.cpp Foo.hpp)
# Target which used Foo will be compiled with this definitions
target_compile_definitions(Foo PUBLIC $<$<CONFIG:Release>:FOO_DEBUG=0>)
target_compile_definitions(Foo PUBLIC $<$<CONFIG:Debug>:FOO_DEBUG=1>)
# This directory will be used as include
target_include_directories(Foo INTERFACE "${CMAKE_INSTALL_PREFIX}/include")
# This library will be linked
target_link_libraries(Foo PUBLIC pthread)
# Regular install
install(FILES Foo.hpp DESTINATION include)
# Install with export set
install(TARGETS Foo DESTINATION lib EXPORT FooTargets)
install(EXPORT FooTargets DESTINATION lib/cmake/Foo)
Installing such project will produce files (CMAKE_DEBUG_POSTFIX
is d
):
include/Foo.hpp
lib/libFoo.a
lib/libFood.a
lib/cmake/Foo/FooTargets-debug.cmake
lib/cmake/Foo/FooTargets-release.cmake
lib/cmake/Foo/FooTargets.cmake
Include FooTargets.cmake
file to import installed library to project. For example using find_package
command (need config, see configure_package_config_file):
add_executable(prog main.cpp)
find_package(Foo REQUIRED) # import Foo
target_link_libraries(prog Foo)
Note that:
- path to
include/Foo.hpp
automatically added to compiler options
- dependend library
pthread
is automatically added to prog
linker option
- definition
FOO_DEBUG=0
added to Release build type
- definition
FOO_DEBUG=1
added to Debug build type
Rationale
So excuse me if this is simple
It is not (:
The root of the problem is ODR (C++ Standard 2011, 3.2 [basic.def.ord], p.3):
Every program shall contain exactly one definition of every non-inline function
or variable that is odr-used in that program; no diagnostic required. The
definition can appear explicitly in the program, it can be found in the
standard or a user-defined library
IMHO good general solution still not exists. Using CMake with imported configuration
can partially helps a little bit, but in some cases you still will get linker errors
(for example if you use library compiled with gcc
, which linked to libstdcxx
by default,
and try to link it to project with clang
compiler, which linked to libcxx
).
Some of this problems (not all, still) can be solved using toolchain files.
See examples.
Related