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.
Related
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();
}
I'm trying to call a function defined in a C file from my CPP code and I think I am having issues getting the correct namespace. When compiling I get the error: "Undefined reference to 'Get'".
My C header:
// c.h
#ifndef C_H
#define C_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
VAL_A1,
VAL_A2
} TYPE_A;
typedef enum
{
VAL_B1,
VAL_B2
} TYPE_B;
typedef enum
{
VAL_C1,
VAL_C2
} TYPE_C;
typedef struct
{
TYPE_B b;
TYPE_C c;
} TYPE_D;
TYPE_A Get(TYPE_B b, TYPE_D *d);
#ifdef __cplusplus
}
#endif
#endif
And my CPP file:
// main.cpp
...
extern "C" {
#include "c.h"
}
...
namespace MyNamespace
{
...
MyClass::MyFunc()
{
TYPE_D d;
// None of these calls will compile
// Get(VAL_B1, &d);
// ::Get(VAL_B1, &d);
}
...
}
I have tried calling without namespace reference and also with the "root" namespace using "::" with no luck. Any help is appreciated. I've read through this which seems to clarify it but I don't really understand it:
using C++ with namespace in C
"Undefined reference" means that the function has been declared (in the header), but not defined. You'll need to define the function in a source file somewhere (presumably the C file you refer to), and make sure that is linked when you build the program.
First, let's note what that error means. An undefined reference at the linker stage means that the compiler is unable to find the instance of something. In this case, the implementation of a function.
Let's look at your code.. There are a few things missing that we need to add to make it compilable:
A definition for Get().
main()
The class definition for MyClass.
Once we added those three fixes, the code compiles without error.
extern "C" { extern "C" {
typedef enum {
VAL_A1,
VAL_A2
} TYPE_A;
typedef enum {
VAL_B1,
VAL_B2
} TYPE_B;
typedef enum {
VAL_C1,
VAL_C2
} TYPE_C;
typedef struct {
TYPE_B b;
TYPE_C c;
} TYPE_D;
TYPE_A Get(TYPE_B b, TYPE_D *d) {
return VAL_A1;
}
}}
namespace MyNamespace {
struct MyClass {
void MyFunc();
};
void MyClass::MyFunc() {
TYPE_D d;
Get(VAL_B1, &d);
::Get(VAL_B1, &d);
}
}
int main() {}
The definition of Get (not shown in the question) also needs to be enclosed in extern "C".
The main difference between C and C++ functions, in practice, is the way they are named in the executable format. C++ functions get "name mangling" treatment by the linker but C functions do not. The linker will see the C++ definition of Get and it will have no idea of its relation to the C declaration, even if they have the same signature.
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);
I've seen some responses to the too few template-parameter-lists problem in classes but I'm getting a similar error in a header file where the declarations seem to be at the name space level. I'm not at all a C++ guy, but I want to figure out what I need to correct in this file to prevent the following error regarding the two lines after the typedef:
too few template-parameter-lists
Here's a file experpt
#ifndef SH_AUDATA_H
#define SH_AUDATA_H
#include "BinaryIO.h"
#include "AudioData.h"
// AuMuLawAudioData
typedef AudioDataImpl<AuMuLaw,BYTE> AuMuLawAudioData ;
inline BYTE AuMuLawAudioData::readValue (BinaryIO* io) const { return (io->read8()) ; }
inline void AuMuLawAudioData::writeValue (BinaryIO* io, BYTE v) const { io->write8(v) ; }
#endif // ndef SH_AUDATA_H
Thanks!
You either need to
indicate your defining a template member using template<> (http://ideone.com/ZWYuCd)
or you should just use the full qualified class name (http://ideone.com/zsmHjG)
Contrast both:
template <typename T> struct X
{
T v;
void foo();
};
typedef X<int> SomeTypedef;
#if 0
template<> void SomeTypedef::foo() {
//
}
#else
template <typename T> void X<T>::foo() {
//
}
#endif
int main()
{
SomeTypedef a;
a.foo();
}
Both the approaches to define foo will work (change #if 0 to #if 1 to "select" the other approach)
I'd like to define a pointer type that is shared between device and host code and internally stores the device and host pointer to the shared memory. I want it to determine at compile time, which pointer to actually return:
#define F inline __host__ __device__
class SharedMemory;
/**
*
* Can only be set by allocating shared memory.
*/
template<typename T>
class SharedMemoryPtr {
public:
SharedMemoryPtr() : hptr(0), dptr(0) {}
//F ~ SharedMemoryPtr() {cudaFreeHost(hptr);} // Should be freed explicitly (?)
// TODO: Don't allow copying/overwriting (at least not without freeing memory...)
F T& operator() () {
#ifdef __CUDACC__
return *dptr;
#else
return *hptr;
#endif
};
F T* operator-> () {
#ifdef __CUDACC__
return dptr;
#else
return hptr;
#endif
};
F T& operator * () {
#ifdef __CUDACC__
return *dptr;
#else
return *hptr;
#endif
};
F T& operator[] (__int64 i) const {
#ifdef __CUDACC__
return *(dptr + i);
#else
return *(hptr + i);
#endif
};
friend SharedMemory;
// TODO: Make obsolete (possible?)
T * getHptr() {return hptr;}
T * getDptr() {return dptr;}
private:
T *hptr, *dptr;
};
class SharedMemory {
public:
template<typename T>
static SharedMemoryPtr<T> allocate(int count = 1) {
assert(count > 0);
SharedMemoryPtr<T> sptr;
cutilSafeCall(
cudaHostAlloc(&sptr.hptr, sizeof(T) * count, cudaHostAllocMapped));
assert(sptr.hptr);
cutilSafeCall(
cudaHostGetDevicePointer(&sptr.dptr, sptr.hptr, 0));
assert(sptr.dptr);
return sptr;
}
};
This works fine as long as I use these pointers in code that is either in a cpp file (where __CUDACC__ is never defined) or a .h file (where __CUDACC__ is only defined if the function is used by some function in a cu file). However in a __host__ function in a .cu file, I get the devptr. Obviously, .cu files are processed exclusively by nvcc. Is there some other preprocessor macro that is defined ONLY for __global__ and __device__ functions, not just everything nvcc happens to process? Or do I need to separate my code?
__CUDA_ARCH__ is actual only for device code. You can specify device code behavior with it.
This macro actually get compute capability of device code (like 200 for 2.0.)