代码之家  ›  专栏  ›  技术社区  ›  Macmade

在共享库中只具有全局状态的C++头

  •  2
  • Macmade  · 技术社区  · 7 年前

    我正在研究一个C++库,我只希望保持头。


    假设这个例子需要一个字符串的全局向量。

    static 函数中的变量:

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

    现在出于某种原因,我还需要将该库打包到macOS框架中。

    在该框架内,有可访问此全局状态的编译代码。

    显然,这是行不通的,因为可执行文件和框架将对静态变量有单独的定义,从而使这个全局状态不那么全局。

    2 回复  |  直到 7 年前
        1
  •  1
  •   Matthieu Brucher    7 年前

    您可以强制符号仅位于一个文件中,例如:

    #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),那么它会变得有点棘手,因为您需要另一个全局标志来说明您是否在框架中并激活导出/导入属性。

        2
  •  1
  •   Julien Villemure-Fréchette    7 年前

    那么:

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

    然后编写一个ODR使用您的定义的.cpp GetGlobalStrings dllexport GlobalString.h 将其链接到dll中应该可以工作。

    // GlobalSring.cpp
    
    #define GLOBAL_STRING_SRC
    #include <GlobalString.h>
    

    inline 关键字保证 GetGlobalString 从链接器看到的不同编译单元中,如果 GetGlobalString 获取已使用的ODR。请放心,C++保证了来自内联函数内的静态变量也被合并。注意 dllimport 论功能 内联 . 我不太熟悉MacOS动态库,但它应该与使用-fvisibility=default标志的clang类似。

    对于C++17,也可以使用内联变量而不是函数:

    inline EXPORT_SYMBOL std::vector<std::string> GlobalString;