C ++ только для заголовков с глобальным состоянием в общей библиотеке - PullRequest
0 голосов
/ 23 ноября 2018

Я работаю над библиотекой C ++, которую в идеале я бы оставил только в заголовках.

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

Я легко могу добиться этого с помощью переменной static внутри функции:

std::vector< std::string > & GetGlobalStrings( void )
{
    static auto g = new std::vector< std::string >();

    return *( g );
}

Это прекрасно работает для исполняемых файлов, использующих библиотеку.

Теперь дляпо какой-то причине мне также нужно упаковать эту библиотеку в инфраструктуру macOS.

Внутри этой инфраструктуры есть скомпилированный код, который будет обращаться к этому глобальному состоянию.
Как и исполняемый файл, связанный с этой платформой.

Очевидно, что это не работает, поскольку исполняемый файл и инфраструктура будут иметь отдельные определения для статической переменной, что делает глобальное состояние не таким уж глобальным.

Есть ли способ сделать это удобным способомобразом?

Ответы [ 2 ]

0 голосов
/ 24 ноября 2018

Как насчет:

// GlobalString.h

#include <string>
#include <vector>

#ifdef _MSC_VER
  #ifdef GLOBAL_STRING_SRC
    #define GLOBAL_STRING_DECLSPEC __declspec(dllexport)
  #else
    #define GLOBAL_STRING_DECLSPEC __declspec(dllimport)
  #endif //GLOBAL_STRING_DECLSPEC
#endif // GLOBAL_STRING_SRC

inline EXPORT_SYMBOL std::vector<std::string>& GetGlobalStrings() noexcept
{
  static std::vector<std::string> retval;
  return retval;
}

Затем напишите .cpp, что ODR использует ваше определение GetGlobalStrings.В Windows объявление функции dllexport является неявным использованием ODR.Компиляция cpp, включающая GlobalString.h и связывание его с dll, должна работать.

// GlobalSring.cpp

#define GLOBAL_STRING_SRC
#include <GlobalString.h>

Ключевое слово inline гарантирует, что несколько определений GetGlobalStrings из разных модулей компиляции, видимых компоновщиком, будут объединенытолько в один, если GetGlobalStrings используется ODR.Будьте уверены, что C ++ гарантирует, что статические переменные из встроенной функции также будут объединены.Обратите внимание, что dllimport для функции определение недопустимо, если определение не объявлено inline.Я не очень знаком с динамическими библиотеками MacOS, но он должен работать аналогично clang с флагом -fvisibility = default.

С C ++ 17 можно также использовать встроенную переменную вместо fuction:

inline EXPORT_SYMBOL std::vector<std::string> GlobalString;
0 голосов
/ 23 ноября 2018

Вы можете заставить символы находиться только в одном файле, например:

#if defined(I_NEED_A_BAD_HACK) || defined(GLOBAL_STATE_STORE)
# define USE_FULL_FUNCTION
#endif

#ifdef USE_FULL_FUNCTION
std::vector< std::string >& GetGlobalStrings()
{
    static std::vector< std::string > g;

    return g;
}
#else
std::vector< std::string >& GetGlobalStrings();
#endif

Затем в одном из ваших фреймворков cpp определите макрос перед включением заголовка.

Теперь, если вам нужно экспортировать символ (в основном Windows, но также Linux / macOS со скрытой видимостью), он становится немного сложнее, так как вам нужен еще один глобальный флаг, говорящий, если вы находитесь в фреймворке, и активация экспорта / импортаattribute.

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

...