I am trying to export a function template with a static variable in the definition.
.dll/Foo.h:
#ifdef _DLL
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
class API Foo
{
public:
template<typename T>
static T& Get()
{
static T _instance;
return _instance;
}
static void Set();
}
I want the calls made by the .dll and .exe to refer to the same "_instance" object. I know I can do that by defining the static variable in the .cpp. But in this case i am dealing with templates so i am kind of stuck.
Edit:
Example of what is happening..
.dll/Foo.cpp:
void Foo::Set()
{
Foo::Get<int>() = 10;
}
.exe/main.cpp:
int main()
{
auto & x = Foo::Get<int>();
x = 3;
std::cout << x; // 3
Foo::Set();
std::cout << x; // 3 (I want it to be 10)
}
you need separate mark every template with API (__declspec(dllexport) or __declspec(dllimport)) and not inline it in class code.
Foo.h file is:
#ifdef _DLL
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
class API Foo
{
public:
template<typename T>
API static T& Get();
static void Set();
};
note that we separate mark Get() with API despite all Foo class also marked with API (class mark have no effect on template function by fact, so need it mark separate). and no implementation of Get here - exported functions anyway can not be inline.
so dll code (Foo.cpp) must look like:
#include "foo.h"
template<typename T>
API T& Foo::Get()
{
__pragma(message("__imp_" __FUNCDNAME__)) // for debug
static T _instance;
return _instance;
}
void Foo::Set()
{
Foo::Get<int>() = 10;
}
note we again explicitly use API (__declspec(dllexport)) in implementation of function body. this is critical important - compiler not warning you, if you skip API here, but without this - Get will be not exported.
for sure that at this point all correct - copy string produced by __pragma(message("__imp_" __FUNCDNAME__)) (it will be look like __imp_??$Get#H#Foo##SAAEAHXZ) and search exactly (symbol to symbol) this string in created .lib file - after you build dll. if it exist - all ok, otherwise no sense continue (with exe)
and in exe :
#include "../foo_dll/foo.h"
Foo::Get<int>() = 3;
Foo::Set();
if (Foo::Get<int>() != 10)
{
__debugbreak();
}
Related
For simplicity, I will omit things like proper typedefs to opaque structs instead of void *, Windows calling conventions, fixed integer types, etc.
Suppose I have the following files:
CApi.h -- Shared library header with C linkage for portability and hiding proprietary code.
#define LIB_API // library import/export details
extern "C" {
typedef int error;
error LIB_API lib_foo_create(void ** foo);
error LIB_API lib_foo_destroy(void * foo);
error LIB_API lib_foo_func(void * foo, int * out);
error LIB_API lib_bar_create(void ** bar);
error LIB_API lib_bar_destroy(void * bar);
error LIB_API lib_bar_func(void * bar, int * out); // Suppose this internally uses Foo::func from CxxApi.hpp with C++17
} // extern C
CxxApi.hpp -- Header only wrapper to simplify API usage.
#include "CApi.h"
namespace lib {
namespace detail {
template < typename Return = void, typename Func, typename... Args >
Return c_api(Func func)
{
// Not sure how this affects ODR if client and provider code use different versions,
// but neither see each other's code usage.
#if __cplusplus >= 201703L // C++17
// more efficient implmentation (e.g. fold expressions)
#else
// fallback implmentation (e.g. recursion)
#endif
}
} // namespace lib::detail
class Foo
{
public:
Foo() { detail::c_api(lib_foo_create, &handle_); }
~Foo() { detail::c_api(lib_foo_destroy, handle_); }
int func() { return detail::c_api<int>(lib_foo_func, handle_); }
private:
void * handle_;
};
struct Bar
{
public:
Bar() { detail::c_api(lib_bar_create, &handle_); }
~Bar() { detail::c_api(lib_bar_destroy, handle_); }
int func() { return detail::c_api<int>(lib_bar_func, handle_); }
private:
void * handle_;
};
} // namespace lib
If I, the API provider, compile this using C++17, but the client using the API uses C++11, is ODR violated with lib::detail::c_api?
I believe it is not because lib_bar_func's definition is in a different translation unit than client code, but I am not positive.
I am working with Unity and I need to pass callback delegate from C# unity script to .dll
There is a api (MyApi.h) that I have on .dll side
typedef void(__stdcall * FuncPtr) (const char * str);
static FuncPtr DebugLog = nullptr;
static void debug_in_unity(std::string message)
{
if (DebugLog)
{
DebugLog(message.c_str());
}
}
extern "C"
{
DllExport void register_debug_callback(FuncPtr callback)
{
if (callback)
{
DebugLog = callback;
}
}
...
}
so, when I call register_debug_callback function from C# side I see that everything is ok and DebugLog assigned as expected.
Then in order to send my log message from .dll side to C# I need to call this function debug_in_unity()
So, I have another myfile.cpp file where I need to use this log function
#include "MyApi.h"
void MyClass::foo()
{
std::string log = "HERE!!!";
debug_in_unity(log);
}
So, everything looks fine, I have a global static method debug_in_unity and global func DebugLog that I assigned previously here register_debug_callback
But what actually is happen is - when I call this method register_debug_callback I see that I assigned DebugLog variable, but then when I call this method debug_in_unity I see that DebugLog is null. Looks like static variable is kind of not global like MyApi.h has instance of DebugLog and myfile.cpp has his own instance. I assume that it is a reason why I see assignment and then I see that the same value is null...
But how to use it properly? How to fix it?
You are breaking the one definition rule. You will need to have one translation unit (.c or .cpp file) defining DebugLog, and the header declaring it extern. Similarly your functions are also defined in multiple translation units.
MyApi.h
typedef void(__stdcall * FuncPtr) (const char * str);
extern FuncPtr DebugLog;
void debug_in_unity(std::string message);
extern "C"
{
DllExport void register_debug_callback(FuncPtr callback);
// ...
}
MyApi.cpp
#include "MyApi.h"
FuncPtr DebugLog = nullptr;
void debug_in_unity(std::string message)
{
if (DebugLog)
{
DebugLog(message.c_str());
}
}
extern "C"
{
DllExport void register_debug_callback(FuncPtr callback)
{
if (callback)
{
DebugLog = callback;
}
}
// ...
}
I have a header-only library that has some additional fail-fast runtime assertions enabled when compiled in debug mode. A simplified version of the header looks like this:
#include <exception>
#ifdef MYDEBUG
# define MYASSERT(condition) do{ if (!(condition)) std::terminate(); } while(0)
#else
# define MYASSERT(condition)
#endif
template<typename T>
class Checker
{
public:
T operator()(T value)
{
MYASSERT(value);
return value;
}
};
If one translation unit includes the header without defining MYDEBUG first, and another one includes it after defining MYDEBUG, and I link the resultant object files together, would that constitute an ODR violation?
How can I avoid this but still allow each TU to independently specify its desired assertion settings when including the header?
If one translation unit includes the header without defining MYDEBUG first, and another one includes it after defining MYDEBUG, and I link the resultant object files together, would that constitute an ODR violation?
Yes, it is a violations of the one-definition-rule. It's a violation of the rule for inline functions that says the inline function definitions must have the exact tokens in all the translation units.
How can I avoid this but still allow each TU to independently specify its desired assertion settings when including the header?
One way to deal with is to define MYASSERT to be file scoped static functions.
#ifdef MYDEBUG
static void MYASSERT(bool condition)
{
if (!(condition))
{
std::terminate();
}
}
#else
static void MYASSERT(bool condition)
{
// Noop
}
#endif
It appears that you cannot. Thanks, #RustyX.
Solution 1: use scoping:
#ifdef MYDEBUG
# define MYASSERT(condition) do{ if (!(condition)) std::terminate(); } while(0)
#else
# define MYASSERT(condition)
#endif
namespace {
template<typename T>
class Checker
{
public:
T operator()(T value)
{
MYASSERT(value);
return value;
}
};
}
This essentially changes Checker to internal linkage, and potentially comes with extra cost, that is it can end up in the final executable multiple times. However, in this particular case there's no extra cost as it will probably be inlined anyway.
Solution 2: parameterize the template on the debug mode:
(Update 3: using template specialization thanks to #Jarod42's suggestion)
#ifdef MYDEBUG
# define MYASSERT(condition) do{ if (!(condition)) std::terminate(); } while(0)
# define MYDEBUG_FLAG true
#else
# define MYASSERT(condition)
# define MYDEBUG_FLAG false
#endif
template<typename T, bool = MYDEBUG_FLAG> class Checker;
template<typename T>
class Checker<T, MYDEBUG_FLAG>
{
public:
T operator()(T value)
{
MYASSERT(value);
return value;
}
};
Then the debug- and non-debug instantiations will be independent of each other.
The nice thing about this is even if one accidentally instantiates Checker<T, !MYDEBUG_FLAG>, it won't compile and hence won't violate ODR (provided only one version, either debug- or non-debug, is ever defined in each TU).
Variant of first RustyX's answer, but fixed I think:
#ifdef MYDEBUG
# define MYDEBUG_FLAG true
#else
# define MYDEBUG_FLAG false
#endif
#define MYASSERT(condition) do{ if (!(condition)) std::terminate(); } while(0)
// Following declaration differs, but doesn't break ODR.
template<typename T, bool = MYDEBUG_FLAG> class Checker;
// And both definitions of specialization.
template <typename T>
class Checker<T, true>
{
public:
T operator()(T value)
{
MYASSERT(value);
return value;
}
};
template <typename T>
class Checker<T, false>
{
public:
T operator()(T value)
{
return value;
}
};
I have this pieces of code:
class DLL_API MyClassWrapper
{
private:
MyClass * m_myClass;
public:
MyClassWrapper(SIZE inputSize);
~MyClassWrapper();
inline int OutputSize();
}
typedef std::shared_ptr<MyClassWrapper> MyClassWrapperPtr;
extern "C"
{
DLL_API MyClassWrapperPtr CreatreMyClassWrapper(SIZE inputSize)
{
return std::make_shared<MyClassWrapper>(inputSize);
}
}
But it doesn't work, with error:
Error 1 error C2526: CreatreMyClassWrapper: C linkage function cannot return C++ class 'std::shared_ptr<_Ty>'
I understand the problem, but how can I fix it?
The options that I can see are:
1- Don't pass a shared pointer. which means that DLL user should delete the pointer after they used it.
2- Don't use extern "C" : which means that I must use mangled names.
Is there any other solution?
Straight to the point, to return C++ object from C function - just returns it via output arguments:
extern "C"
{
DLL_API void CreatreMyClassWrapper(SIZE inputSize, SomeClass* outputPtr)
{
*outputPtr = SomeClass(....);
}
}
In your example SomeClass == MyClassWrapperPtr, so:
extern "C"
{
DLL_API void CreatreMyClassWrapper(SIZE inputSize, MyClassWrapperPtr* outputPtr)
{
*outputPtr = make_shared<MyClassWrapper>(inputSize);
}
}
Consider however to change your interface a little, because in current shape you need to be sure that your applications and DLLs shall use the same compiler, linker, settings, libraries...*
You might want to export Create and Delete from your DLL to be sure memory management will occur in your DLL (this is based on this answer:
DLL
extern "C"
{
DLL_API MyClassWrapper* CreateMyClassWrapper(SIZE inputSize)
{
return new MyClassWrapper(inputSize);
}
DLL_API void DeleteMyClassWrapper(MyClassWrapper* wrapper)
{
delete wrapper;
}
}
Application
shared_ptr<MyClassWrapper> myClassWrapper(CreateMyClassWrapper(inputSize),
DeleteMyClassWrapper);
// in someFile.h or someFile.cpp
TEST()
{
"example test", []
{
EXPECT(0 == 1);
}
}
TEST_END()
// in main.cpp
int main() { ssvu::Test::runAllTests(); }
#define TEST() static RunOnCtor UNIQUENAME(__LINE__) { []{ getStaticTests().push_back({
#define TEST_END() });}};
struct RunOnCtor { RunOnCtor(std::function<void()> f) { f(); } };
I've created some unit testing macros that work both in header (useful for my header-only libraries) and source files.
TEST() creates a static instance of RunOnCtor, which, on construction, executes a lambda which inserts the test lambda into a std::vector of tests. runAllTests() runs every test in that vector.
I have created a DISABLE_TEST define that simply puts return; at the beginning of the RunOnCtor lambda, so that no tests are added to the internal vector. However, I would like to prevent unnecessary construction of static objects when tests are disabled.
Is there a way to completely ignore everything between TEST() and TEST_END()? Something like commenting it out. Or would emptying out RunOnCtor (empty struct) make the compiler avoid static constructions?
I think this should work:
#define TEST() struct UNIQUENAME(__LINE__) { void f() {
#define TEST_END() } };
The following is based on #Angew 's answer but uses standard preprocessor definitions. The class then defines a function within the class declaration, which in C++ forces it to be inline. Because the class is never instantiated and the function is never called, no code is ever generated.
#define CAT(a, ...) PCAT(a, __VA_ARGS__)
#define PCAT(a, ...) a ## __VA_ARGS__
#define TEST() class CAT(Obfuscate_, __LINE__) { void f() {
#define TEST_END() } };
int c;
TEST()
int a = 7;
int b = a * 17;
c = b + 4;
return;
TEST_END()
Here's Godbolt's handy-dandy compiler explorer to prove that GCC, CLANG, and ICC produce no code for the above: https://godbolt.org/g/BXKDNF