C++ header-only with global state in a shared library












2














I'm working on a C++ library that I would ideally keep header-only.



A specific part of this library requires a global state.

Let's say it needs a global vector of strings for this example.



I can easily achieve this with a static variable inside a function:



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

return *( g );
}


This works great for executables using the library.



Now for some reason, I also need to package that library inside a macOS framework.



Inside that framework, there's compiled code that will access this global state.

So does the executable linked with that framework.



Obviously this doesn't work, as the executable and the framework will have separate definitions for the static variable, thus making this global state not so global.



Is there any way to accomplish this in a convenient manner?










share|improve this question


















  • 2




    Do you need to allocate that vector dynamically? Can't you just do static std::vector<std::string> g; return g;?
    – Galik
    Nov 23 '18 at 18:12










  • Without a shared library that will support the static variable? Doubtful. You will need to make it non inline, perhaps only the framework has access to the function implementation, and the executable to just the prototype. Do you have a speed issue by making it non header only?
    – Matthieu Brucher
    Nov 23 '18 at 18:13












  • I think this can be done with some platform-specific tricks. I don't know anything about MacOS, but on Windows, for example, you could do this with a shared memory block.
    – Peter Ruderman
    Nov 23 '18 at 18:20










  • @Galik I'm allocating dynamically so I don't get a warning about requiring an exit-time destructor (-Wexit-time-destructors). Anyway, problem is the same regardless of the allocation type. Even with auto allocation, executable and framework will still have separate definitions.
    – Macmade
    Nov 23 '18 at 18:20










  • @MatthieuBrucher No speed issue, header-only is simply more convenient for the library purpose.
    – Macmade
    Nov 23 '18 at 18:21
















2














I'm working on a C++ library that I would ideally keep header-only.



A specific part of this library requires a global state.

Let's say it needs a global vector of strings for this example.



I can easily achieve this with a static variable inside a function:



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

return *( g );
}


This works great for executables using the library.



Now for some reason, I also need to package that library inside a macOS framework.



Inside that framework, there's compiled code that will access this global state.

So does the executable linked with that framework.



Obviously this doesn't work, as the executable and the framework will have separate definitions for the static variable, thus making this global state not so global.



Is there any way to accomplish this in a convenient manner?










share|improve this question


















  • 2




    Do you need to allocate that vector dynamically? Can't you just do static std::vector<std::string> g; return g;?
    – Galik
    Nov 23 '18 at 18:12










  • Without a shared library that will support the static variable? Doubtful. You will need to make it non inline, perhaps only the framework has access to the function implementation, and the executable to just the prototype. Do you have a speed issue by making it non header only?
    – Matthieu Brucher
    Nov 23 '18 at 18:13












  • I think this can be done with some platform-specific tricks. I don't know anything about MacOS, but on Windows, for example, you could do this with a shared memory block.
    – Peter Ruderman
    Nov 23 '18 at 18:20










  • @Galik I'm allocating dynamically so I don't get a warning about requiring an exit-time destructor (-Wexit-time-destructors). Anyway, problem is the same regardless of the allocation type. Even with auto allocation, executable and framework will still have separate definitions.
    – Macmade
    Nov 23 '18 at 18:20










  • @MatthieuBrucher No speed issue, header-only is simply more convenient for the library purpose.
    – Macmade
    Nov 23 '18 at 18:21














2












2








2







I'm working on a C++ library that I would ideally keep header-only.



A specific part of this library requires a global state.

Let's say it needs a global vector of strings for this example.



I can easily achieve this with a static variable inside a function:



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

return *( g );
}


This works great for executables using the library.



Now for some reason, I also need to package that library inside a macOS framework.



Inside that framework, there's compiled code that will access this global state.

So does the executable linked with that framework.



Obviously this doesn't work, as the executable and the framework will have separate definitions for the static variable, thus making this global state not so global.



Is there any way to accomplish this in a convenient manner?










share|improve this question













I'm working on a C++ library that I would ideally keep header-only.



A specific part of this library requires a global state.

Let's say it needs a global vector of strings for this example.



I can easily achieve this with a static variable inside a function:



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

return *( g );
}


This works great for executables using the library.



Now for some reason, I also need to package that library inside a macOS framework.



Inside that framework, there's compiled code that will access this global state.

So does the executable linked with that framework.



Obviously this doesn't work, as the executable and the framework will have separate definitions for the static variable, thus making this global state not so global.



Is there any way to accomplish this in a convenient manner?







c++ global-variables dynamic-linking dynamic-library header-only






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 23 '18 at 18:02









Macmade

41.9k1192113




41.9k1192113








  • 2




    Do you need to allocate that vector dynamically? Can't you just do static std::vector<std::string> g; return g;?
    – Galik
    Nov 23 '18 at 18:12










  • Without a shared library that will support the static variable? Doubtful. You will need to make it non inline, perhaps only the framework has access to the function implementation, and the executable to just the prototype. Do you have a speed issue by making it non header only?
    – Matthieu Brucher
    Nov 23 '18 at 18:13












  • I think this can be done with some platform-specific tricks. I don't know anything about MacOS, but on Windows, for example, you could do this with a shared memory block.
    – Peter Ruderman
    Nov 23 '18 at 18:20










  • @Galik I'm allocating dynamically so I don't get a warning about requiring an exit-time destructor (-Wexit-time-destructors). Anyway, problem is the same regardless of the allocation type. Even with auto allocation, executable and framework will still have separate definitions.
    – Macmade
    Nov 23 '18 at 18:20










  • @MatthieuBrucher No speed issue, header-only is simply more convenient for the library purpose.
    – Macmade
    Nov 23 '18 at 18:21














  • 2




    Do you need to allocate that vector dynamically? Can't you just do static std::vector<std::string> g; return g;?
    – Galik
    Nov 23 '18 at 18:12










  • Without a shared library that will support the static variable? Doubtful. You will need to make it non inline, perhaps only the framework has access to the function implementation, and the executable to just the prototype. Do you have a speed issue by making it non header only?
    – Matthieu Brucher
    Nov 23 '18 at 18:13












  • I think this can be done with some platform-specific tricks. I don't know anything about MacOS, but on Windows, for example, you could do this with a shared memory block.
    – Peter Ruderman
    Nov 23 '18 at 18:20










  • @Galik I'm allocating dynamically so I don't get a warning about requiring an exit-time destructor (-Wexit-time-destructors). Anyway, problem is the same regardless of the allocation type. Even with auto allocation, executable and framework will still have separate definitions.
    – Macmade
    Nov 23 '18 at 18:20










  • @MatthieuBrucher No speed issue, header-only is simply more convenient for the library purpose.
    – Macmade
    Nov 23 '18 at 18:21








2




2




Do you need to allocate that vector dynamically? Can't you just do static std::vector<std::string> g; return g;?
– Galik
Nov 23 '18 at 18:12




Do you need to allocate that vector dynamically? Can't you just do static std::vector<std::string> g; return g;?
– Galik
Nov 23 '18 at 18:12












Without a shared library that will support the static variable? Doubtful. You will need to make it non inline, perhaps only the framework has access to the function implementation, and the executable to just the prototype. Do you have a speed issue by making it non header only?
– Matthieu Brucher
Nov 23 '18 at 18:13






Without a shared library that will support the static variable? Doubtful. You will need to make it non inline, perhaps only the framework has access to the function implementation, and the executable to just the prototype. Do you have a speed issue by making it non header only?
– Matthieu Brucher
Nov 23 '18 at 18:13














I think this can be done with some platform-specific tricks. I don't know anything about MacOS, but on Windows, for example, you could do this with a shared memory block.
– Peter Ruderman
Nov 23 '18 at 18:20




I think this can be done with some platform-specific tricks. I don't know anything about MacOS, but on Windows, for example, you could do this with a shared memory block.
– Peter Ruderman
Nov 23 '18 at 18:20












@Galik I'm allocating dynamically so I don't get a warning about requiring an exit-time destructor (-Wexit-time-destructors). Anyway, problem is the same regardless of the allocation type. Even with auto allocation, executable and framework will still have separate definitions.
– Macmade
Nov 23 '18 at 18:20




@Galik I'm allocating dynamically so I don't get a warning about requiring an exit-time destructor (-Wexit-time-destructors). Anyway, problem is the same regardless of the allocation type. Even with auto allocation, executable and framework will still have separate definitions.
– Macmade
Nov 23 '18 at 18:20












@MatthieuBrucher No speed issue, header-only is simply more convenient for the library purpose.
– Macmade
Nov 23 '18 at 18:21




@MatthieuBrucher No speed issue, header-only is simply more convenient for the library purpose.
– Macmade
Nov 23 '18 at 18:21












2 Answers
2






active

oldest

votes


















1














You could force the symbols to be in only one file, for instance:



#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


Then in one of your framework cpp, define the macro before including the header.



Now, if you need to export the symbol (Windows mainly but also Linux/macOS with visibility hidden), then it gets a little bit trickier, as you need another global flag saying if you are in the framework or not and activating the export/import attribute.



It's definitely not great, but at least you ensure that you have only one instance of the static variable in one file. Also works properly with a static library, of course.






share|improve this answer























  • Thanks. I'm definitely looking in this way, and I actually tried that. Unfortunately, leads to packaging issues, as I would also like to be able to create an executable on other platforms, using only the headers. This would require people to define that macro, which I'd like to avoid...
    – Macmade
    Nov 23 '18 at 18:37






  • 1




    Let's add another hack then...
    – Matthieu Brucher
    Nov 23 '18 at 18:38






  • 1




    Well, I finally made this work, although I had to tweak a bit the build settings in Xcode to allow linking an executable with the headers-only library or with a framework exposing the headers-only library. Anyway, this was the way to go, so marking this as the accepted answer. Thanks : )
    – Macmade
    Nov 23 '18 at 22:58



















1














What about:



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


Then write a .cpp that ODR uses your definition of GetGlobalStrings. On Windows, declaring an function dllexport is an implicit ODR use. Compiling a cpp that includes GlobalString.h and linking it into the dll should work.



// GlobalSring.cpp

#define GLOBAL_STRING_SRC
#include <GlobalString.h>


The inline keyword guarantees that multiple definitions of GetGlobalStrings from different compilation units seen by the linker will be merged into only one if GetGlobalStrings gets ODR used. Be reassured that C++ guarantees that static variables from within inline function are also merged. Note that dllimport on function definition is illegal unless the definition is declared inline. I am not much familar with MacOS dynamic libraries, but it should work similarly with clang with -fvisibility=default flag.



With C++17 one could also probably use an inline variable instead of a fuction:



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





share|improve this answer





















  • Thanks for the answer. Found a working solution for macOS, not sure I'll run into the same issues on Windows... But I'll keep your answer in mind : )
    – Macmade
    Nov 23 '18 at 22:54






  • 1




    This will still output a stern warning saying that the function is defined when it shouldn't. You will have to mix the two answers to get a good result.
    – Matthieu Brucher
    Nov 23 '18 at 23:09











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53451198%2fc-header-only-with-global-state-in-a-shared-library%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














You could force the symbols to be in only one file, for instance:



#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


Then in one of your framework cpp, define the macro before including the header.



Now, if you need to export the symbol (Windows mainly but also Linux/macOS with visibility hidden), then it gets a little bit trickier, as you need another global flag saying if you are in the framework or not and activating the export/import attribute.



It's definitely not great, but at least you ensure that you have only one instance of the static variable in one file. Also works properly with a static library, of course.






share|improve this answer























  • Thanks. I'm definitely looking in this way, and I actually tried that. Unfortunately, leads to packaging issues, as I would also like to be able to create an executable on other platforms, using only the headers. This would require people to define that macro, which I'd like to avoid...
    – Macmade
    Nov 23 '18 at 18:37






  • 1




    Let's add another hack then...
    – Matthieu Brucher
    Nov 23 '18 at 18:38






  • 1




    Well, I finally made this work, although I had to tweak a bit the build settings in Xcode to allow linking an executable with the headers-only library or with a framework exposing the headers-only library. Anyway, this was the way to go, so marking this as the accepted answer. Thanks : )
    – Macmade
    Nov 23 '18 at 22:58
















1














You could force the symbols to be in only one file, for instance:



#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


Then in one of your framework cpp, define the macro before including the header.



Now, if you need to export the symbol (Windows mainly but also Linux/macOS with visibility hidden), then it gets a little bit trickier, as you need another global flag saying if you are in the framework or not and activating the export/import attribute.



It's definitely not great, but at least you ensure that you have only one instance of the static variable in one file. Also works properly with a static library, of course.






share|improve this answer























  • Thanks. I'm definitely looking in this way, and I actually tried that. Unfortunately, leads to packaging issues, as I would also like to be able to create an executable on other platforms, using only the headers. This would require people to define that macro, which I'd like to avoid...
    – Macmade
    Nov 23 '18 at 18:37






  • 1




    Let's add another hack then...
    – Matthieu Brucher
    Nov 23 '18 at 18:38






  • 1




    Well, I finally made this work, although I had to tweak a bit the build settings in Xcode to allow linking an executable with the headers-only library or with a framework exposing the headers-only library. Anyway, this was the way to go, so marking this as the accepted answer. Thanks : )
    – Macmade
    Nov 23 '18 at 22:58














1












1








1






You could force the symbols to be in only one file, for instance:



#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


Then in one of your framework cpp, define the macro before including the header.



Now, if you need to export the symbol (Windows mainly but also Linux/macOS with visibility hidden), then it gets a little bit trickier, as you need another global flag saying if you are in the framework or not and activating the export/import attribute.



It's definitely not great, but at least you ensure that you have only one instance of the static variable in one file. Also works properly with a static library, of course.






share|improve this answer














You could force the symbols to be in only one file, for instance:



#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


Then in one of your framework cpp, define the macro before including the header.



Now, if you need to export the symbol (Windows mainly but also Linux/macOS with visibility hidden), then it gets a little bit trickier, as you need another global flag saying if you are in the framework or not and activating the export/import attribute.



It's definitely not great, but at least you ensure that you have only one instance of the static variable in one file. Also works properly with a static library, of course.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 23 '18 at 18:40

























answered Nov 23 '18 at 18:27









Matthieu Brucher

12.7k22140




12.7k22140












  • Thanks. I'm definitely looking in this way, and I actually tried that. Unfortunately, leads to packaging issues, as I would also like to be able to create an executable on other platforms, using only the headers. This would require people to define that macro, which I'd like to avoid...
    – Macmade
    Nov 23 '18 at 18:37






  • 1




    Let's add another hack then...
    – Matthieu Brucher
    Nov 23 '18 at 18:38






  • 1




    Well, I finally made this work, although I had to tweak a bit the build settings in Xcode to allow linking an executable with the headers-only library or with a framework exposing the headers-only library. Anyway, this was the way to go, so marking this as the accepted answer. Thanks : )
    – Macmade
    Nov 23 '18 at 22:58


















  • Thanks. I'm definitely looking in this way, and I actually tried that. Unfortunately, leads to packaging issues, as I would also like to be able to create an executable on other platforms, using only the headers. This would require people to define that macro, which I'd like to avoid...
    – Macmade
    Nov 23 '18 at 18:37






  • 1




    Let's add another hack then...
    – Matthieu Brucher
    Nov 23 '18 at 18:38






  • 1




    Well, I finally made this work, although I had to tweak a bit the build settings in Xcode to allow linking an executable with the headers-only library or with a framework exposing the headers-only library. Anyway, this was the way to go, so marking this as the accepted answer. Thanks : )
    – Macmade
    Nov 23 '18 at 22:58
















Thanks. I'm definitely looking in this way, and I actually tried that. Unfortunately, leads to packaging issues, as I would also like to be able to create an executable on other platforms, using only the headers. This would require people to define that macro, which I'd like to avoid...
– Macmade
Nov 23 '18 at 18:37




Thanks. I'm definitely looking in this way, and I actually tried that. Unfortunately, leads to packaging issues, as I would also like to be able to create an executable on other platforms, using only the headers. This would require people to define that macro, which I'd like to avoid...
– Macmade
Nov 23 '18 at 18:37




1




1




Let's add another hack then...
– Matthieu Brucher
Nov 23 '18 at 18:38




Let's add another hack then...
– Matthieu Brucher
Nov 23 '18 at 18:38




1




1




Well, I finally made this work, although I had to tweak a bit the build settings in Xcode to allow linking an executable with the headers-only library or with a framework exposing the headers-only library. Anyway, this was the way to go, so marking this as the accepted answer. Thanks : )
– Macmade
Nov 23 '18 at 22:58




Well, I finally made this work, although I had to tweak a bit the build settings in Xcode to allow linking an executable with the headers-only library or with a framework exposing the headers-only library. Anyway, this was the way to go, so marking this as the accepted answer. Thanks : )
– Macmade
Nov 23 '18 at 22:58













1














What about:



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


Then write a .cpp that ODR uses your definition of GetGlobalStrings. On Windows, declaring an function dllexport is an implicit ODR use. Compiling a cpp that includes GlobalString.h and linking it into the dll should work.



// GlobalSring.cpp

#define GLOBAL_STRING_SRC
#include <GlobalString.h>


The inline keyword guarantees that multiple definitions of GetGlobalStrings from different compilation units seen by the linker will be merged into only one if GetGlobalStrings gets ODR used. Be reassured that C++ guarantees that static variables from within inline function are also merged. Note that dllimport on function definition is illegal unless the definition is declared inline. I am not much familar with MacOS dynamic libraries, but it should work similarly with clang with -fvisibility=default flag.



With C++17 one could also probably use an inline variable instead of a fuction:



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





share|improve this answer





















  • Thanks for the answer. Found a working solution for macOS, not sure I'll run into the same issues on Windows... But I'll keep your answer in mind : )
    – Macmade
    Nov 23 '18 at 22:54






  • 1




    This will still output a stern warning saying that the function is defined when it shouldn't. You will have to mix the two answers to get a good result.
    – Matthieu Brucher
    Nov 23 '18 at 23:09
















1














What about:



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


Then write a .cpp that ODR uses your definition of GetGlobalStrings. On Windows, declaring an function dllexport is an implicit ODR use. Compiling a cpp that includes GlobalString.h and linking it into the dll should work.



// GlobalSring.cpp

#define GLOBAL_STRING_SRC
#include <GlobalString.h>


The inline keyword guarantees that multiple definitions of GetGlobalStrings from different compilation units seen by the linker will be merged into only one if GetGlobalStrings gets ODR used. Be reassured that C++ guarantees that static variables from within inline function are also merged. Note that dllimport on function definition is illegal unless the definition is declared inline. I am not much familar with MacOS dynamic libraries, but it should work similarly with clang with -fvisibility=default flag.



With C++17 one could also probably use an inline variable instead of a fuction:



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





share|improve this answer





















  • Thanks for the answer. Found a working solution for macOS, not sure I'll run into the same issues on Windows... But I'll keep your answer in mind : )
    – Macmade
    Nov 23 '18 at 22:54






  • 1




    This will still output a stern warning saying that the function is defined when it shouldn't. You will have to mix the two answers to get a good result.
    – Matthieu Brucher
    Nov 23 '18 at 23:09














1












1








1






What about:



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


Then write a .cpp that ODR uses your definition of GetGlobalStrings. On Windows, declaring an function dllexport is an implicit ODR use. Compiling a cpp that includes GlobalString.h and linking it into the dll should work.



// GlobalSring.cpp

#define GLOBAL_STRING_SRC
#include <GlobalString.h>


The inline keyword guarantees that multiple definitions of GetGlobalStrings from different compilation units seen by the linker will be merged into only one if GetGlobalStrings gets ODR used. Be reassured that C++ guarantees that static variables from within inline function are also merged. Note that dllimport on function definition is illegal unless the definition is declared inline. I am not much familar with MacOS dynamic libraries, but it should work similarly with clang with -fvisibility=default flag.



With C++17 one could also probably use an inline variable instead of a fuction:



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





share|improve this answer












What about:



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


Then write a .cpp that ODR uses your definition of GetGlobalStrings. On Windows, declaring an function dllexport is an implicit ODR use. Compiling a cpp that includes GlobalString.h and linking it into the dll should work.



// GlobalSring.cpp

#define GLOBAL_STRING_SRC
#include <GlobalString.h>


The inline keyword guarantees that multiple definitions of GetGlobalStrings from different compilation units seen by the linker will be merged into only one if GetGlobalStrings gets ODR used. Be reassured that C++ guarantees that static variables from within inline function are also merged. Note that dllimport on function definition is illegal unless the definition is declared inline. I am not much familar with MacOS dynamic libraries, but it should work similarly with clang with -fvisibility=default flag.



With C++17 one could also probably use an inline variable instead of a fuction:



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






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 23 '18 at 22:50









Julien Villemure-Fréchette

43517




43517












  • Thanks for the answer. Found a working solution for macOS, not sure I'll run into the same issues on Windows... But I'll keep your answer in mind : )
    – Macmade
    Nov 23 '18 at 22:54






  • 1




    This will still output a stern warning saying that the function is defined when it shouldn't. You will have to mix the two answers to get a good result.
    – Matthieu Brucher
    Nov 23 '18 at 23:09


















  • Thanks for the answer. Found a working solution for macOS, not sure I'll run into the same issues on Windows... But I'll keep your answer in mind : )
    – Macmade
    Nov 23 '18 at 22:54






  • 1




    This will still output a stern warning saying that the function is defined when it shouldn't. You will have to mix the two answers to get a good result.
    – Matthieu Brucher
    Nov 23 '18 at 23:09
















Thanks for the answer. Found a working solution for macOS, not sure I'll run into the same issues on Windows... But I'll keep your answer in mind : )
– Macmade
Nov 23 '18 at 22:54




Thanks for the answer. Found a working solution for macOS, not sure I'll run into the same issues on Windows... But I'll keep your answer in mind : )
– Macmade
Nov 23 '18 at 22:54




1




1




This will still output a stern warning saying that the function is defined when it shouldn't. You will have to mix the two answers to get a good result.
– Matthieu Brucher
Nov 23 '18 at 23:09




This will still output a stern warning saying that the function is defined when it shouldn't. You will have to mix the two answers to get a good result.
– Matthieu Brucher
Nov 23 '18 at 23:09


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53451198%2fc-header-only-with-global-state-in-a-shared-library%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

Calculate evaluation metrics using cross_val_predict sklearn

Insert data from modal to MySQL (multiple modal on website)