C++ header-only with global state in a shared library
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
|
show 8 more comments
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
2
Do you need to allocate that vector dynamically? Can't you just dostatic 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
|
show 8 more comments
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
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
c++ global-variables dynamic-linking dynamic-library header-only
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 dostatic 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
|
show 8 more comments
2
Do you need to allocate that vector dynamically? Can't you just dostatic 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
|
show 8 more comments
2 Answers
2
active
oldest
votes
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.
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
add a comment |
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;
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
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
add a comment |
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.
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
add a comment |
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.
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.
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
add a comment |
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
add a comment |
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;
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
add a comment |
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;
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
add a comment |
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;
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;
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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