Trouble retrieving and storing pointers to OpenGL functions manually - c++

I have some trouble retrieving and storing manually the pointers to OpenGL functions, here is a "simplified snippet" version of my code :
#ifdef WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
class CGLManager
{
public:
// Manager functions
bool GetAnyGLFuncAddress( const char *_cName, void *_pFunc );
bool LoadFunctions( void );
// OpenGL functions
void (APIENTRY *glBegin)( GLenum mode );
void (APIENTRY *glEnd)( void );
void (APIENTRY *glVertex3f)( GLfloat x, GLfloat y, GLfloat z );
private:
#ifdef WIN32
HMODULE m_hLib; // opengl32.dll
#else
void *m_hLib; // libGL.so
#endif
};
And here's the source :
extern CGLManager gGL;
// GetAnyGLFuncAddress - Attempt to retrieve the OpenGL function named "_cName" and store it in "_pFunc", returns true if success or false otherwise
bool CGLManager::GetAnyGLFuncAddress( const char *_cName, void *_pFunc )
{
#ifdef WIN32
// Similar to https://www.opengl.org/wiki/Load_OpenGL_Functions#Windows
_pFunc = (void *)wglGetProcAddress( _cName );
if ( _pFunc == 0 || (_pFunc == (void *)0x1) || (_pFunc == (void *)0x2) || (_pFunc == (void *)0x3) || (_pFunc == (void *)-1) )
_pFunc = (void *)GetProcAddress( m_hLib, _cName );
#else
// TODO: Test this
// According to some websites, NVIDIA drivers prefer the ARB implementation over the core one
_pFunc = (void *)glXGetProcAddressARB( _cName );
if ( _pFunc == 0 || (_pFunc == (void *)0x1) || (_pFunc == (void *)0x2) || (_pFunc == (void *)0x3) || (_pFunc == (void *)-1) )
_pFunc = (void *)glXGetProcAddress( _cName );
#endif
return (_pFunc != NULL);
}
// LoadFunctions - Attempt to retrieve all used OpenGL functions, returns true if all of them were retrieved or false if there is a single failure
bool CGLManager::LoadFunctions( void )
{
if ( !(GetAnyGLFuncAddress( "glBegin", &gGL.glBegin )) )
return false;
if ( !(GetAnyGLFuncAddress( "glEnd", &gGL.glEnd )) )
return false;
if ( !(GetAnyGLFuncAddress( "glVertex3f", &gGL.glVertex3f )) )
return false;
return true;
}
Here's how my manager work in general : it first check which renderer the game's engine uses (Software, OpenGL or Direct3D), if it's not OpenGL, then we stop getting any further. Otherwise, we load the library (opengl32.dll or libGL.so) and we check if it's good or not (again, if failed, we stop), we retrieve and store the pointers to OpenGL's functions (glBegin, glEnd, glVertex3f) with the LoadFunctions method and we return if everything's fine or something wrong happened.
Now the problem : the GetAnyGLFuncAddress method retrieve successfully OpenGL functions (in other words, glBegin will return true, glARandomMethodThatDontExist will return false) but for some reason, gGL.glBegin (and it's "friends") in LoadFunctions doesn't get updated and it will be always NULL causing a crash.
I have been trying for hours to find out a solution by searching on Internet and on StackOverflow but I haven't found any answer that can give me the solution to the problem.
In many websites and answers I've found on StackOverflow, a lot of people suggested to use an OpenGL loading library like GLEW and even the OpenGL wiki recommend it. However, due to the nature of the environment I'm working on, I can't use those kind of libraries and neither I can't use OpenGL functions directly, I know I'm going through the painful way by doing everything manually but I have no other choice.
Thank you for your answers.

bool CGLManager::GetAnyGLFuncAddress( const char *_cName, void *_pFunc )
This is just common, broken C++. _pFunc is a void*. The pointer is the value. Changing the value of _pFunc will not change the value of the variable passed in.
You should either just return the pointer (with NULL representing the failure condition), or _pFunc should be a void**. That will likely require a cast from the caller though, and GetAnyGLFuncAddress would need to do *_pFunc = to set the value.
If you're going to return the function pointer, then you need to cast the returned void* to the appropriate function pointer type before storing it. This is why you often see OpenGL loaders use typedefs for function pointer types.
typedef void (APIENTRY *(PFN_GLBEGIN))( GLenum );
...
PFN_GLBEGIN glBegin;
...
glBegin = static_cast<PFN_GLBEGIN>(GetAnyGLFuncAddress("glBegin"));
Something like that.

Forgetting about what your ultimate goal is, I see basic C++ mistakes.
Let's cut out all of the code that is irrelevant and focus on this:
bool CGLManager::GetAnyGLFuncAddress( const char *_cName, void *_pFunc )
{
_pFunc = (void *)wglGetProcAddress( _cName ); // <-- This sets the local pointer
//...
}
Then you call the above like this:
bool CGLManager::LoadFunctions( void )
{
if ( !(GetAnyGLFuncAddress( "glBegin", &gGL.glBegin )) )
return false;
}
You're passing the address in the second argument, but inside the function GetAnyGLFuncAddress, you're not updating the value so that the new value is reflected back to the caller. You're setting the local value instead, thus gGL.glBegin (and all the other addresses from the other two calls), will not be set.
Inside of GetAnyGLFuncAddress, I would have expected this to work:
bool CGLManager::GetAnyGLFuncAddress( const char *_cName, void *_pFunc )
{
*_pFunc = (void *)wglGetProcAddress( _cName ); // <-- Note the *
//...
}
And any subsequent usage of pFunc inside of GetAnyGLFuncAddress also should reflect the dereferenced value.
Another solution (and since this is C++), you can forego the void * C-like coding and make the function a template that takes a function pointer type as the template argument:
template <typename FnPtr>
bool CGLManager::GetAnyGLFuncAddress( const char *_cName, FnPtr* _pFunc )
{
*_pFunc = reinterpret_cast<FnPtr>(wglGetProcAddress( _cName ));
//...
}
Since the type is now FnPtr*, whatever you pass in will automatically have FnPtr be of that type. No more void * (except for the return value of wglGetProcAddress, which is casted).

*gl*GetProcAddres is specified only for returning entry point addresses for extended functionality. It is not required that it returns addresses for functions found in the operating systems OpenGL ABI requirements (OpenGL-1.1 for Windows, OpenGL-1.2 for Linux Softare Base (LSB) 4, OpenGL-2.1 for LSB-5).
In general if your program binary is directly linked to the API library (stub) (in contrast to using a loader that loads the API library (stub) at runtime, dynamically), it's quity silly to retrieve functions being part of the OS's OpenGL ABI contract with *gl*GetProcAddress as these function are available through the regular API library anyway. wglGetProcAddress is exported alongside OpenGL-1.1 functions as is glXGetProcAddress exported alongside all OpenGL-1.2 functions (at least), so if your program sees the *GetProcAddress functions it also sees the other OpenGL functions.
The only reason to load all OpenGL symbols through GetProcAddress is if you load opengl32.dll with LoadLibrary or libGL.so with dlopen.

Related

How do I use GLADcallback?

I'm using glad to generate OpenGL bindings, and have generated a debug build which includes the following:
// this symbol only exists if generated with the c-debug generator
#define GLAD_DEBUG
typedef void (* GLADcallback)(const char *name, void *funcptr, int len_args, ...);
/*
* Sets a callback which will be called before every function call
* to a function loaded by glad.
*
*/
GLAPI void glad_set_pre_callback(GLADcallback cb);
/*
* Sets a callback which will be called after every function call
* to a function loaded by glad.
*
*/
GLAPI void glad_set_post_callback(GLADcallback cb);
The documentation gave an example how to define this callback, which looks like this:
void _post_call_callback_default(const char *name, void *funcptr, int len_args, ...) {
GLenum error_code;
error_code = glad_glGetError();
if (error_code != GL_NO_ERROR) {
fprintf(stderr, "ERROR %d in %s\n", error_code, name);
}
}
What I don't understand is how I'm supposed to access the varargs. I'm guessing that they are the values that are passed to the OpenGL function, and thus can be any type. However, I must specify the type to va_arg in order to access the values.
I feel that the parameter len_args is hinting that there is some way to iterate over the varargs, but I don't understand how it's supposed to be used without knowing the types. How are they meant to be used?
You have the source code of glad.c whenever the glad_set_post_callback function is called. There you can see that the parameters depends on which function was called. So I think you need to check the name/funcptr parameter.
For example if glEnable was called then you have:
void APIENTRY glad_debug_impl_glEnable(GLenum arg0) {
_pre_call_callback("glEnable", (void*)glEnable, 1, arg0);
glad_glEnable(arg0);
_post_call_callback("glEnable", (void*)glEnable, 1, arg0);
}
which means that the first parameter is a GLenum. See this question an-example-of-use-of-varargs-in-c on how to use variable arguments:
It would be something like this (not tested):
void _post_call_callback_default(const char *name, void *funcptr, int len_args, ...) {
GLenum error_code;
error_code = glad_glGetError();
if (error_code != GL_NO_ERROR && funcptr == (void*)glEnable /* or strcmp(name,"glError") == 0*/) {
va_list ap;
va_start(ap, len_args);
GLenum arg0 = va_arg(ap, GLenum);
va_end(ap);
printf("Called glError(%d) with Error %d\n", arg0, error_code);
}
}
You can so decide for which functions you want a better debug log. I am not aware if there is already some free code that gives a better debug output.
Maybe it's better to compare funcptr with the pointer to glEnable instead of comparing the string name with "glError". I didn't tested it. The code above is just an example, I would write it differently.

passing pointers to extern C function in a DLL from VB

I am a C++ (MSVC) writer, VB newbie trying to assist an expert VB.net writer who has just not done this task before.
We wish to develop both C/C++ and VB applications to use a DLL written in C++ with C extern-ed API functions. The C++ program is working just fine. It's VB where we are having difficulties.
The DLL provides an extern C function:
RegisterCallback( void* cbFuncPtr, void* dataPtr );
NOTE 1: See my note below for a design change and the reasons we made it.
NOTE 2: Additional update added as an answer below.
where the callback function havs this C typedef:
typedef (void)(* CALL_NACK)(void*);
The cbFuncPtr is expected to be a function pointer to some VB function that will get called as the CALL_BACK. The dataPtr is a pointer to a data structure that has this C definition:
typedef struct
{
int retCode;
void* a_C_ptr;
char message[500];
} cbResponse_t;
where a_C_ptr is an internal pointer in the DLL that the VB can cast tolong`. It uniquely identifies where in the DLL the callback was made and allows the VB function to recognize calls from same/different locations.
We are able to access and run the RegisterCallback() function from VB just fine. Logging shows we get there and that data is passed in. It is the actual data that seems to be the problem.
In reading about a million forum entries we have learned that VB doesn't know what pointers are and that a VB structure is more than just organized memory. We're pretty sure the "address" of a VB structure is not what C thinks an address is. We've seen repeated references to "marshaling" and "managed data", but lack enough understanding to know what that is telling us.
How should we code VB to give the DLL the execution address of its callback function and how do we code up a VB construct that the DLL can fill in just as it does for C++?
Might we need a DLL function where the calling app can say "C" or "VB" andhave the DLL handle the sturcture pointers differently? If so, how would one code up C to fill in the VB structure?
This is a bit too big and deep to just be an edit to the original posting...
From the link posted by #DaveNewman, I extracted this gem:
Here's a bit about the compact framework, but it's the same in the
grown-ups framework:
The .NET Compact Framework supports automatic marshaling of structures
and classes that contain simple types. All fields are laid out
sequentially in memory in the same order as they appear in the
structure or class definition. Both classes and structures appear in
native code as pointers to C/C++ structs.
Objects in the managed heap can be moved around in memory at any time
by the garbage collector, so their physical addresses may change
without notice. P/Invoke automatically pins down managed objects
passed by reference for the duration of each method call. This means
pointers passed to unmanaged code will be valid for that one call.
Bear in mind that there is no guarantee that the object will not be
moved to a different memory address on subsequent calls.
http://msdn.microsoft.com/en-us/library/aa446538.aspx#netcfmarshallingtypes_topic6
This is major hurdle for a RegisterCallback( fcnPtr, dataPtr) function. The pointer passed in at registration time could change at any time the RegisterCallback() is not the current statement. The posting author summed it up this way
You don't need to do anything as the structures are pinned automatically for duration of the call.
implying, of course, not pinned down outside the call.
For this reason we decided on a design change to have the response structure built in, so to speak, the C/C++ world of the DLL, not in VB's space. That way it'll stay put. The actual callback function's signature will remain unchanged so the VB program can know where the DLL put the response. This also allows the responders in the DLL to allocate separate response structures for separate needs.
Once again my update is too large for a mere comment!
Update 18 Apr 2013:
Well, the attempt to use the code from Calling Managed Code from Unmanaged Code cited above was a bust. We ended up having to add /clr to the DLL make turning the DLL into managed code, which made it unusable from a C application.
We are now testing the example at Callback Sample which I was able to show made a DLL that worked with both VB and C++. You'd need to have the PinvokeLib.dll Source to make this work.
Here is the code for the C++ (C really) tester. Compiled as a MSVC project.
NOTE: Notice the __cdecl in this line:
typedef bool (__cdecl *FPtr)(BOOL_FP_INT fp, int i );
It was the secret I had to find. The DLL and this app are compiled with __cdecl linkage, not __stdcall. They are the default in VC++ and I just used the defaults. I tried changing everything to __stdcall but that didn't work. Has to be __cdecl.
// PinvokeTester.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <cstdlib>
#include <string.h>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <Windows.h>
#define PINVOKELIB_API __declspec(dllimport)
HINSTANCE hLib; // Windows DLL handle
bool CALLBACK VBCallBack( int value );
bool AttachLibrary( void );
void * GetFuncAddress( HINSTANCE hLib, const char* procname );
int main(int argc, char* argv[])
{
if ( !AttachLibrary() )
{
printf( "Lib did not attach.\n" );
exit(1);
}
typedef bool (CALLBACK *BOOL_FP_INT)(int i );
typedef bool (__cdecl *FPtr)(BOOL_FP_INT fp, int i );
FPtr TestCallBack = (FPtr)GetFuncAddress( hLib, "TestCallBack" );
TestCallBack( (BOOL_FP_INT)VBCallBack, 255 );
return 0;
}
bool CALLBACK VBCallBack( int value )
{
printf( "\nCallback called with param: %d", value);
return true;
}
bool AttachLibrary( void )
{
// Get a var for the IPC-dll library.
std::string dllName;
/*--- First, link to the IPC-dll library or report failure to do so. ---*/
dllName = ".\\PinvokeLib";
if ( NULL == (hLib = LoadLibraryA( dllName.c_str() )) )
{
printf( "\nERROR: Library \"%s\" Not Found or Failed to Load. \n\n", dllName.c_str() );
printf( "\"%s\"\n", GetLastError() );
return false;
}
return true;
}
//=====================================================================
void * GetFuncAddress( HINSTANCE hLib, const char* procname )
{
void * procAddr = NULL;
procAddr = (void *)GetProcAddress( hLib, procname );
// If the symbol wasn't found, handle error ---------------------
if ( NULL == procAddr )
{
std::cout << "ERROR: Could not get an address for the \""
<< procname << "\" function. : "
<< GetLastError() << std::endl;
exit( 7 );
procAddr = (void*)NULL;
}
return procAddr;
}

Debug version only crash

I'm having a debug only crash. I'm using Eclipse's gdb.
If I'm not failing reading it, the crash seems to occur when passing an object (not by reference nor pointer) to an interface method, precisely when copying a "many" (typedef std::list<boost::any> many;) member during it's copy constructor called to send a copy to the method.
I'm not using debug builds for boost, nor other external builds, just for the code I'm compiling, so, could this be the cause?
Any other ideas at what may be the cause?
class Message {
public:
static const int MAX_LEVEL=5;
Message(int type=0, int destination=0);
virtual ~Message();
int type;
int destination[MAX_LEVEL];
int level;
many message;
};
And the crashing sector, inside init() on Game3DWin: (Even though I'm building in Debug mode, there's no _DEBUG define since I didn't build the Debug binaries for the libs)
bool Game3DWin::init(){
#ifdef _DEBUG
pluginsCfg = "lib/plugins_d.cfg";
resourcesCfg = "res/resources_d.cfg";
#elif OGRE_PLATFORM == OGRE_PLATFORM_WIN32
pluginsCfg = "lib/pluginsWin.cfg";
resourcesCfg = "res/resources.cfg";
#else
pluginsCfg = "lib/plugins.cfg";
resourcesCfg = "res/resources.cfg";
#endif
ogreRoot=boost::make_shared<Ogre::Root>(pluginsCfg, "config.cfg");
if(!(ogreRoot->restoreConfig() || ogreRoot->showConfigDialog())){
return false;
}
window = ogreRoot->initialise(true, "Crewon CLASH!");
loadResourceCfgFile();
guiRenderer = &CEGUI::OgreRenderer::bootstrapSystem();
CEGUI::SchemeManager::getSingleton().create( "TaharezLook.scheme" );
CEGUI::System::getSingleton().setDefaultFont( "DejaVuSans-10" );
CEGUI::System::getSingleton().setDefaultMouseCursor( "TaharezLook", "MouseArrow" );
CEGUI::Window* myRoot = CEGUI::WindowManager::getSingleton().createWindow( "DefaultWindow", "_MasterRoot" );
CEGUI::System::getSingleton().setGUISheet( myRoot );
CRengine::Message msg=CRengine::Message( (int)CRengine::MESSAGE_TYPE::INPUT_INIT );
msg.message.push_front(window);
this->broadcaster.lock()->receiveMessage( msg ); //Crash here
//Unreached code due to crash
}
broadcaster is a pointer to Messageable, an interface.
class Messageable {
public:
virtual ~Messageable() {};
virtual bool receiveMessage(CRengine::Message) = 0;
};
broadcaster initialization (factory method to be able to store a "this" smart pointer):
Game3DWin* Game3DWin::create(boost::shared_ptr<CRengine::Messageable> caster, int processType, int order){
Game3DWin* temp= new Game3DWin(processType, order);
temp->broadcaster=caster;
bool success=temp->init();
if(!success){
delete temp;
temp=NULL;
}else{
temp->checkRoom(); }
return temp;
}
The above is called here:
bool MainManager::start( boost::shared_ptr<MainManager> thisMM ){
//Some code
boost::shared_ptr<Game3DWin> win;
win.reset( Game3DWin::create(thisMM, CRengine::MAIN_PROCESS_TYPES::PROCESS_GUI) );
//Some code
}
start() called from the main, which passes the pointer to MainManager
boost::shared_ptr<CRengine::MainManager> app =boost::make_shared<CRengine::MainManager>();
app->start(app);
Message implementation:
Message::Message(int type, int destination): type(type), level(0){
for(int ii=0;ii<MAX_LEVEL;ii++){
this->destination[ii]=-1;
}
this->destination[0]=destination;
}
Message::~Message() { }
window is Ogre::RenderWindow* from OGRE 3D open source rendering engine. I tried to cast it to (int) before pushing it into many in case it tried to call a destructor or something, but, still, same crash.
This is an extended comment, too long to fit in a comment.
Message lacks an implemented constructor and destructor. Either simplfy the class while confirming the problem still occurs, or expose that implementation to us.
window is a variable of unknown type. As the list of boost::any that you are reporting as crashing contains the window type, knowing what it is may just be somewhat useful.
this->broadcaster.lock() will be a null shared_ptr if the weak_ptr has gone away. Always, always, always do shared_ptr<foo> pFoo = this->broadcaster.lock(); then use pFoo (or whatever name) after checking that it is valid (evaluating it in a boolean context).
boost::weak_ptr<CRengine::Messageable> caster -- do you not know if this exists? You probably want a boost::shared_ptr here, so that the caster is at least known to exist during creation of the Game3DWin.
Same here: boost::weak_ptr<MainManager> thisMM -- probably should be a shared_ptr.
The issue was none of the aforementioned. It was caused by Eclipse being unable to clean. This was caused due to using "External Builder", mingw32-make.exe, which in the makefile ran a del <Filelist> and Windows7 seems to have some issue with this and it's parameters, so the clean did nothing.
Since I was working with Debug as active build, I got the crash due to lack of clean, but when I switched to Release it was unaffected since it had to mostly rebuild everything.
Manual delete of the contents of <project>/Debug and <project>/Release fixed the problem.

I need advice about a LNK2019 workaround

As previously discussed here, I'm trying to find a workaround for the LNK2019 issue that arises when building a static library which utilizes C++ templates, and separating the source from the header to keep the code private from other projects. I believe I've nearly come to a working conclusion (for my particular situation), but I'm not entirely sure if this is the correct/best way to go about it and was wondering if anyone has any suggestions, improvements/comments to add?
The goal is to do some type checking to see if the template's signature matches the target prototype function's signature, do some private processing, and return whether or not it was sucessful. NOTE that I have removed SdkHookMgr.h and SdkHookMgr.cpp from the prior version of the solution in the above link, and merged everything back into SdkLib.h and SdkLib.cpp, into a static class for a bit of clarity.
SdkLib.h:
#include <typeinfo>
#ifdef MY_EXPORTS
# define MYDECL __declspec(dllexport)
#else
# define MYDECL
#endif
// Prototypes
typedef HMODULE (WINAPI *HookLoadLibraryA)( LPCSTR lpFileName );
//...
class CHook;
class CHookManager;
MYDECL BOOL WINAPI ValidateHook( CHook *hook );
class CHook
{
public:
CHook() : m_type(NULL), m_target(NULL), m_result(FALSE) {};
CHook( const char *type, PVOID target ) : m_type(type), m_target(target) {
m_result = ValidateHook(this);
};
const char *m_type;
PVOID m_target;
BOOL m_result;
};
class CHookManager
{
public:
template <typename HookFunction> static BOOL Hook(HookFunction target)
{
const type_info& type = typeid(HookFunction);
CHook *hook = new CHook( type.name(), target );
return hook->m_result;
}
};
SdkLib.cpp:
#include <SdkLib.h>
IDXDECL BOOL WINAPI ValidateHook( CHook *hook )
{
// Do type checking, private processing, etc here...
return TRUE;
}
DemoDLL.cpp:
#include <SdkLib.h>
HMODULE WINAPI Hooked_LoadLibraryA( LPCSTR lpFileName )
{
DebugBreak();
}
// The function that starts the rollercoaster.
// - Syntax: Hook< prototype >( target )
if!(CHookManager::Hook<HookLoadLibraryA>(Hooked_LoadLibraryA))
cout << "Failed to create hook for LoadLibraryA!" << endl;
You may find that the results of typeid are not consistent between the DLL and the main program. (See, for example, typeid result across different dll's.)
Since your list of possible hooks is limited, it strikes me that overloaded functions would be a better choice than templates. You'd then have no DLL issues, and the validity of each hook would be checked at compile time. Here's an example of the sort of thing I'm thinking of; obviously in practice you'd split this into separate definition and declaration, with the definitions living in the DLL so it's all cleanly separated out.
class CHookManager {
public:
BOOL Hook(HookLoadLibraryA hook) {
assert(sizeof hook<=sizeof(uintptr_t));
return ValidateHook((uintptr_t)hook,"LoadLibraryA");
}
BOOL Hook(HookLoadLibraryW hook) {
assert(sizeof hook<=sizeof(uintptr_t));
return ValidateHook((uintptr_t)hook,"LoadLibraryW");
}
};
(Note that this shows up one disadvantage of this approach - you can only have one hook per function signature. I mention this for completeness' sake, but I'll assume this hasn't proven an issue.)
(You might like to replace the assert with a compile-time assert, if you have one.)
ValidateHook would use strcmp to figure out which hook is being hooked. Once it's figured out which hook it is, it would then cast the uintptr_t to the appropriate function pointer type. It knows the pointer was originally of the correct type for that hook, because you're using the C++ overload mechanism to do it all. (Or you could have an enum, say, for all the hook types, rather than passing in a string - it's up to you. The key part is that you have full control over the values being passed, so that the DLL and the calling code are definitely using matching values.)
This code would be a little tiresome to generate, but if you already have the list of typedef names then you could create the corresponding code using regular expression search and replace, or keyboard macros, in your editor of choice. Or you could use something like the so-called "X-Macro" to automate the generation of the whole thing.

Using LLVM JIT code to encode a program to call C++ code

My project has a C++ library that I want to allow the user to use via some programming language to be JIT'd to call functions in said library. For the sake of simplicity, assume the library has classes like:
class item {
public:
item();
item( int );
~item();
// ...
};
class item_iterator {
public:
virtual ~item_iterator();
virtual bool next( item *result ) = 0;
};
class singleton_iterator : public item_iterator {
public:
singleton_iterator( item const &i );
// ...
};
I'm aware that LLVM doesn't know anything about C++ and that one way to call C++ functions is to wrap them in C thunks:
extern "C" {
void thunk_item_M_new( item *addr ) {
new( addr ) item;
}
void thunk_singleton_iterator_M_new( singleton_iterator *addr, item *i ) {
new( addr ) singleton_iterator( *i );
}
bool thunk_iterator_M_next( item_iterator *that, item *result ) {
return that->next( result );
}
} // extern "C"
The first problem is how to allocate an item from LLVM. I know how to create StructTypes and add fields to them, but I don't want to have to parallel the C++ class layout -- that's tedious and error-prone.
The idea I got was simply to add a char[sizeof(T)] as the only field to a StructType for a C++ class type:
StructType *const llvm_item_type = StructType::create( llvm_ctx, "item" );
vector<Type*> llvm_struct_types;
llvm_struct_types.push_back( ArrayType::get( IntegerType::get( llvm_ctx, 8 ), sizeof( item ) ) );
llvm_item_type->setBody( llvm_struct_types, false );
PointerType *const llvm_item_ptr_type = PointerType::getUnqual( llvm_item_type );
I would think that, because it's a StructType, the alignment would be correct and the sizeof(item) would get the size right. Will that work? Is there a better way?
The second problem is that, unlike the C++ class hierarchy, there's no inheritance relationship between StructTypes. If I create a Function that takes an llvm_iterator_type but try to build a Function object using an llvm_singleton_iterator_type, the LLVM verifyModule() function complains at me:
Call parameter type does not match function signature!
So then I thought I'd simply use void* everywhere:
Type *const llvm_void_type = Type::getVoidTy( llvm_ctx );
PointerType *const llvm_void_ptr_type = PointerType::getUnqual( llvm_void_type );
but verifyModule() still complains at me because, apparently, there's no automatic casting to void* types in LLVM. How can I solve this problem?
It turns out that using char[sizeof(T)] is a reasonable way to gets StructTypes to be the correct size -- at least one other person from the LLVM mailing list does this.
As for the "Call parameter type does not match function signature!" errors, a solution to that is simply to have all thunks use void* and use static_casts inside. When passing arguments to the thunks, use the CreateBitCast() IRBuilder function (since casts-tovoid are not automatic in LLVM).