Заголовки библиотеки и #define

Я не был уверен, что искать для этого. Так что извините, если это просто. Но позвольте мне изложить сценарий и посмотреть, какие ответы там.

Допустим, у меня есть библиотека, которая определяет такую ​​структуру:

struct Example {
    int a;
#if B_ENABLED
    int b;
#endif
};

Этот заголовок устанавливается как часть установки библиотеки в целом. Мой вопрос здесь заключается в том, что если моя библиотека определяет B_ENABLED, она будет иметь структуру с этими двумя переменными. Однако, если мое приложение не определяет это также. Затем он будет интерпретировать заголовок как определяющий структуру только с одним членом.

Является ли лучший способ справиться с этим, просто чтобы создать какой-то заголовок "options", который будет включать все #defines, которые были указаны в сборке библиотеки?

Моя библиотека строится с помощью CMAKE. Таким образом, решение CMAKE для этого - дополнительный кредит =D.

1 ответ

Решение

Решение № 1 (настройка + установка)

Включают config.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 вывод команды configure_file:

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)

входной файл config.hpp.in использовать специальные cmakedefine директива:

#ifndef CONFIG_HPP_
#define CONFIG_HPP_

#cmakedefine FOO_DEBUG

#endif // CONFIG_HPP_

Обратите внимание, что при использовании установленной библиотеки в другом проекте:

  • вам все еще нужно указать включаемые каталоги для библиотеки
  • если у вашей библиотеки есть зависимости, вам нужно связать их вручную
  • у вас не может быть 2 конфигурационных файлов (Debug/Release)

Решение № 2 (рекомендуется экспорт / импорт)

Команда install(EXPORT ...) может содержать всю информацию об использовании библиотеки (также называемые требованиями к использованию: включая определения, связанную библиотеку, конфигурацию и т. д.):

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)

Установка такого проекта даст файлы (CMAKE_DEBUG_POSTFIX является 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

Включают FooTargets.cmake файл для импорта установленной библиотеки в проект. Например, используя find_package команда (нужна настройка, см. configure_package_config_file):

add_executable(prog main.cpp)
find_package(Foo REQUIRED) # import Foo
target_link_libraries(prog Foo)

Обратите внимание, что:

  • путь к include/Foo.hpp автоматически добавляется в опции компилятора
  • зависимая библиотека pthread автоматически добавляется в prog опция компоновщика
  • определение FOO_DEBUG=0 добавлен в тип сборки Release
  • определение FOO_DEBUG=1 добавлен в тип сборки Debug

обоснование

So excuse me if this is simple

Это не (:

Корень проблемы в ODR (C++ Standard 2011, 3.2 [basic.def.ord], с.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

ИМХО хорошего общего решения пока не существует. Использование CMake с импортированной конфигурацией может немного помочь, но в некоторых случаях вы все равно получите ошибки компоновщика (например, если вы используете библиотеку, скомпилированную с gcc, который связан с libstdcxx по умолчанию, и попробуйте связать его с проектом clang компилятор, который связан с libcxx). Некоторые из этих проблем (не все, все же) могут быть решены с помощью файлов инструментов. Смотрите примеры.

связанные с

Другие вопросы по тегам