Overriding C++ entry point to be a STATIC method of a class - c++

Preface and the problem
I'm currently studying C++ programming language and game programming.
At the moment, I'm working on a simple game engine just to practice 'consistency' and architecture of the API, and due to this reason the idea of mimicing C# 'Program' class appeared.
C# Entry point:
class Program
{
static void Main(string[] args)
{
// Do stuff.
}
}
C++ analogue required:
class Program
{
public:
static void Main()
{
// Do stuff. 'args' analogue can be ignored, if necessary.
}
};
Is it possible to somehow, using linker options, redefine entry point to be a static class method?
Related experience and my theories on this topic
The main reason, why I think, this should be possible is described in the following piece of code (that was successfully compiled using mingw-w64).
#include <iostream>
class Main
{
public:
static void Foo() { std::cout << "Main::Foo\n"; }
};
void localFoo() { std::cout << "localFoo\n"; }
void callFunc(void(*funcToCall)())
{
funcToCall();
}
int main()
{
callFunc(localFoo);
callFunc(Main::Foo); // Proves that Main::Foo has the same interface as localFoo.
return 0;
}
(Refers to Win32 API) I abstracted Win32 API into classes and used window procedure as a static member of class. It was absolutely correct to Win32 WNDCLASS and I could even use static members of my class inside this procedure.
Conslusion I made: static fields and methods technically have no differences between global variables and functions, and, since that, they can replace some code, that dates back to C (default entry point, for example).
Notes
Both MinGW and MSVC (Visual Studio or cmd) solutions are acceptable.
The author of the post is extremely grateful for any information provided :3

Is it possible to somehow, using linker options, redefine entry point to be a static class method?
No. Not if you want to use the C++ runtime library, at any rate. main (or WinMain) is called by the runtime library once it has completed initialising itself, and that call is hard-coded in the runtime library itself.
The MSVC linker lets you specify an alternative entry point with the /ENTRY switch (see here), but if you do that you will bypass the runtime library initialisation code and that will break things.

Related

How to check if function is declared in global scope at compile time

Let I have a header, for example #include <GL/gl.h>. It contains subset of OpenGL API functions. I need something like this:
static_assert(has_glDrawArraysIndirect::value, "There is no glDrawArraysIndirect");
Or even better:
PFNGLDRAWARRAYSINSTANCEDPROC ptr_glDrawArraysIndirect = ptr_to_glDrawArraysIndirect::ptr;
Where ptr_to_glDrawArraysIndirect::ptr unrolls to pointer to glDrawArraysIndirect if it's defined or to a stub function stub_glDrawArraysIndirect otherwise.
My target operating system is very specific. Any linker based solution (like GetProcAddress or dlsym) doesn't work for me, since there is no dynamic linker. More than, my driver doesn't provide glXGetProcAdrress nor wglGetProcAddress, basically there there is no way to query pointer at run time by function name (Actually, I want to implement such a mechanism).
Any ideas?
Here is an answer that can detect it at compile time and produce a boolean value. It works by creating a template function of the same name in a namespace and then using that namespace inside of the is_defined() function. If the real glDrawArraysIndirect() exists it will take preference over the template version. If you comment out the first declaration of glDrawArraysIndirect() the static assert at the bottom will trigger.
Test on GodBolt
#include <type_traits>
enum GLenum {};
void glDrawArraysIndirect(GLenum, const void*);
namespace detail {
struct dummy;
template<typename T>
dummy& glDrawArraysIndirect(T, const void*);
}
constexpr bool is_defined()
{
using namespace detail;
using ftype = decltype(glDrawArraysIndirect(GLenum(), nullptr));
return std::is_same<ftype, void>();
}
static_assert(is_defined(), "not defined");
With a little tweak you can make your custom function the template and use a similar trick
ideone.com
#include <type_traits>
#include <iostream>
//#define USE_REAL
enum GLenum {TEST};
typedef void (*func_type)(GLenum, const void*);
#ifdef USE_REAL
void glDrawArraysIndirect(GLenum, const void*);
#endif
namespace detail {
struct dummy {};
template<typename T = dummy>
void glDrawArraysIndirect(GLenum, const void*, T = T())
{
std::cout << "In placeholder function" << std::endl;
}
}
void wrapDraw(GLenum x, const void* y)
{
using namespace detail;
glDrawArraysIndirect(x, y);
}
#ifdef USE_REAL
void glDrawArraysIndirect(GLenum, const void*)
{
std::cout << "In real function" << std::endl;
}
#endif
int main()
{
wrapDraw(TEST, nullptr);
}
Include the expression sizeof(::function) somewhere. (If the function exists then asking for the size of the pointer to the function is a perfectly valid thing to do).
It will be benign at runtime, and :: forces the use of the function declared at global scope.
Of course, if function does not exist at global scope, then compilation will fail.
Along with other errors, the compiler will issue a specific error if you were to write something on the lines of
static_assert(sizeof(::function), "There is no global function");
My target operating system is very specific. Any linker based solution (like GetProcAddress or dlsym) doesn't work for me, since there is no dynamic linker.
Is this an embedded system or just a weirdly stripped down OS running on standard PC hardware?
More than, my driver doesn't provide glXGetProcAdrress nor wglGetProcAddress, basically there there is no way to query pointer at run time by function name
The abiliy to query function pointers at runtime does not depend on the presence of a dynamic linker. Those two are completely orthogonal and even a purely statically linked embedded OpenGL implementation can offer a GetProcAddress interface just fine. Instead of trying to somehow solve the problem at compile or link time, I'd rather address the problem by implementing a GetProcAddress for your OpenGL driver; you can do that even if the driver is available as only a static library in binary form. Step one:
Create function pointer stubs for each and every OpenGL function, statically initialized to NULL and attributed weak linkage. Link this into a static library you may call gl_null_stubs or similar.
Create a GetProcAddress function that for every OpenGL function there is returns the pointer to the function symbol within the scope of the function's compilation unit.
Now link your weird OpenGL driver with the stubs library and the GetProcAddress implementation. For every function there is, the weak linkage of the stub will the static library symbol to take precedence. For all OpenGL symbols not in your driver the stubs will take over.
There: Now you have a OpenGL driver library that has a GetProcAddress implementation. That wasn't that hard, was it?
How to check if function is declared in global scope at compile time?
My target operating system is very specific...
A possible solution might be, if you are using a recent GCC -probably as a cross-compiler for your weird target OS and ABI- to customize the gcc (or g++ etc...) compiler with your own MELT extension.
MELT is a domain specific language, implemented as a free software GCC plugin (mostly on Linux), to customize the GCC compiler.

C++/Ada Link Errors

I am not familiar with link errors at all so I was hoping someone could shed some light on these errors...
I am working with a Legacy Ada program. I am developing a C++ Extension in which the Ada will use a proxy to call the C++ functions. The C++ compiles cleanly without any warnings. However I am getting the following Undefined Symbol errors:
__nw__FUi
__walkback
__dl__FPv
The code base is as follows:
#include "cppProxy.h"
extern classHandler *classPtr;
void processData(void* ioBuffer)
{
classPtr->processData(ioBuffer);
}
Header File:
#include "classHandler.h"
extern "C" void processData(void* ioBuffer);
classHandler.cpp
extern "C"
{
classHandler* create()
{
return new classHandler;
}
void destroy(classHandler *p)
{
delete p;
}
}
void processData(*ioBuffer)
{
int idx;
data = static_cast<int*>(ioBuffer);
idx = (data[0] >> 16);
returnData[idx] = data;
}
classHandler.h
class classHandler
{
public:
classHandler();
~classHandler();
void processData(void* ioBuffer);
};
typedef classHandler classPtr;
typedef void destroy_t(classHandler*);
Now the objective is to have the C++ keep track of the object so I was trying to create a singleton that would then be called. Looking at the current state of the code I am trying to figure out where this is since I have done multiple changes trying to fix the linker error.
Overall I am wondering if this is truly a linking error or an issue with my class implementation. I am leaning towards the latter but still uncertain on how to resolve the issue.
Once again the design I am going for is as follows:
Implemented:
Ada calls the C++ to process data.
C++ parses the data and stores it locally.
Not Implemented:
Ada calls the C++ to retrieve the data.
C++ does a lookup and returns data array.
Any help would be appreciated on this since I am lost in my own code at the moment. Thanks!
EDIT1:
The Ada code is too robust but I know with certainty that that side is correct. As for the compiler, I am using Concurrent ANSI C/C++ compiler (PowerPC) – 5.4 (005). I CANNOT change compilers. The first two fragments are the proxy layer of the code. This is what the Ada portion uses to interface into the C++ code.

MFC-related crash when calling constructors

I'm currently writing an application using MFC and CLR in visual studio, and my program is crashing whenever I call the constructor of a class I've written (the class is to control a camera over USB).
I've got a base class CameraBase:
class CameraBase
{
public:
virtual bool getFrame(cv::Mat& outImage) { return true; };
};
and a derived class LumeneraCamera (for the specific camera):
class LumeneraCamera : public CameraBase
{
public:
DLL_API LumeneraCamera();
DLL_API bool connect(int cameraNum);
DLL_API bool disconnect();
DLL_API bool getFrame(cv::Mat& outImage);
private:
//Bunch of misc variables
};
These classes are compiled into a DLL and accessed from another program:
int main()
{
cout << "Initing camera" << endl;
camera = new LumeneraCamera();
//More operations
}
When I run the program, it prints Initing camera and then fails because of an assertion in dllinit.cpp (line 133: VERIFY(AfxInitExtensionModule(controlDLL, hInstance));). It crashes before executing anything in the constructor. I'm not really sure what the problem is but it seems tied to MFC, so I'm currently looking into untangling my project from MFC entirely. Any suggestions or fixes are appreciated!
According to MSDN, if your DLL is dynamically linked against the MFC DLLs, each function exported from this DLL which call into MFC must have the AFX_MANAGE_STATE macro added at the very beginning of the function:
AFX_MANAGE_STATE(AfxGetStaticModuleState());
I eventually solved it by disabling MFC - a library I was using suggested MFC but as far as I can tell works fine without it.

Using different incompatible versions of a CORBA Interface in the same app/module?

Given two IDL definitions: (I'm only implementing a client, the server side is fixed.)
// Version 1.2
module Server {
interface IObject {
void Foo1();
void Foo2() raises(EFail);
string Foo3();
// ...
}
};
// Version 2.3
module Server {
interface IObject {
// no longer available: void Foo1();
void Foo2(string x) raises(ENotFound, EFail); // incompatible change
wstring Foo3();
// ...
}
};
(Edit Note: added Foo3 method that cannot be overloaded because the return type changed.)
Is it somehow possible to compile both stub code files in the same C++ CORBA Client App?
Using the defaults of an IDL compiler, the above two IDL definitions will result in stub code that cannot be compiled into the same C++ module, as you'd get multiple definition errors from the linker. The client however needs to be able to talk to both server versions.
What are possible solutions?
(Note: We're using omniORB)
(Adding answer from one Stefan Gustafsson, posted in comp.object.corba 2011-03-08)
If you look at it as a C++ problem instead of a CORBA problem, the
solution is C++ namespaces.
You could try to wrap the different implementations in different C++
namespaces.
Like:
namespace v1 {
#include "v1/foo.h" // From foo.idl version 1
}
namespace v2 {
#include "v2/foo.h" // from foo.idl version 2
}
And to be able to compile the C++ proxy/stub code you need to create C++
main files like:
// foo.cpp
namespace v1 {
#include "v1/foo_proxy.cpp" // filename depend on IDL compiler
}
namespace v2 {
#include "v2/foo_proxy.cpp"
}
This will prevent the C++ linker complaining since the names will be
different. Of course you
could run into problems with C++ compilers not supporting nested
namespaces..
A second solution is to implement the invocation using DII, you could
write a C++ class
class ServerCall {
void foo2_v1() {
// create request
// invoke
}
void foo2_v2(String arg) {
// create_list
// add_value("x",value,ARG_IN)
// create_request
// invoke
}
}
By using DII you can create any invocation you like, and can keep full
control of your client code.
I think this is a good idea, but I haven't been able to try it out yet, so there may lurk some unexpected surprises wrt to things no longer being in the global namespace.
What comes to my mind would be splitting the client code into separate libraries for each version.
Then you can select the correct client depending on the version to be used.
In a recent project we handled this by introducing a service layer with no dependency to the CORBA IDL.
For example:
class ObjectService
{
public:
virtual void Foo1() = 0;
virtual void Foo2() = 0;
virtual void Foo2(const std::string &x) = 0;
};
For each version, create a class derived from ObjectService and implement the operations by
calling the CORBA::Object. Each derived class must be in separate library.
In the client implementation, you only operate on instances of ObjectService.
CORBA::Object_var remoteObject=... // How to get the remote object depends on your project
ObjectService *serviceObject=0;
// create a service object matching the remote object version
// Again, this is project specific
switch (getRemoteObjectVersion(remoteObject))
{
case VERSION_1_2:
serviceObject=new ServiceObjectImpl12(remoteObject);
break;
case VERSION_2_3:
serviceObject=new ServiceObjectImpl23(remoteObject);
break;
default:
// No matching version found, throw exception?
break;
}
// Access remote object through service object
serviceObject->Foo2("42");

How to manipulate/return data with dynamically loaded functions (dlopen)?

I've spent days reading and re-reading every tutorials I've found on the subject, and spent hours (and even days) browsing related questions here at SO, but I still can't get the following to work. Accept my apologies if this is a duplicate: chances are that I've seen and re-read many times the duplicate questions but couldn't understand the relevance of the answers to my problem. With that out of the way...
I'm trying to implement a plugin architecture for my Application. Plugins are compiled and installed as libraries. At run time, the Application then uses dlopen() / dlsym() to load and link to the plugin's functions.
The idea is that plugins (libraries) will implement a set of functions to return data to the main Application, or manipulate data passed from the Application.
In order to test this idea, I tried to implement a function (inside the plugin) that would return the (human readable) name of the plugin itself (as a std::string). I thought that would be something simple to start with.... :-/
Here is what I got so far:
// Plugin.cpp
extern "C" void plugin_name(std::string *name) {
name = new std::string("Example plugin name");
}
// Application.cpp
void* handle = dlopen("libplugin.so", RTLD_LAZY);
typedef void (*plugin_t)(std::string*);
dlerror(); // Reset errors.
plugin_t call_plugin_name = (plugin_t) dlsym(handle, "plugin_name");
// ... Some error handling code.
std::string my_plugin_name;
call_plugin_name(&my_plugin_name);
dlclose(handle);
// More code that displays my_plugin_name.
I've tried many different combinations, including one that seemed more straigtforward (but didn't work any better) where the plugin name is returned:
// Plugin.cpp
extern "C" std::string plugin_name(void) {
return std::string("Example plugin name");
}
I know I'm close: the code compiles and the Application stopped crashing ;)
However, I've got an empty space where I'd expect seeing the actual plugin name.
All the tutorials I've read so far go very quickly over the mechanism by which data is passed both ways: plugin <=> Application. What I'm trying to do with a "simple" std::string, I wish to do later with much more complex objects (i.e. a plugin function would take an object by reference and change some of its properties). The tutorials more or less all stop at the point of creating a pointer with dlsym() and do not give much examples on how to use this pointer.
So, how to do all that?
Another pertinent question: do I use a common header that I'd use both with the Application and with the plugin and where I'd define the function calls signature? How would I do this and how would that help?
The signature of a function is generated from its name and argument types (return value type doesn't matter). When you declare function with extern "C", C symbol naming scheme is used which apparently can't handle C++ types like std::string. That's why passing std::string as an arguments doesn't work.
I can't explain why returning std::string doesn't work. Maybe different calling conventions are used.
Anyway the correct way of importing C++ code from a shared library is to return pointers to C++ types from entry points. And this entry points have to have arguments with types available in C. (Entry point is a documented function exported from a shared library)
Here is a good article on basic aspects of loading C++ classes from shared libraries. This article will answer your question throughly.
Please note that there are pitfalls when using exceptions thrown from a shared library to the main applications. And with dynamic_cast of objects created inside a library. I've mentioned this topics so that you could be somewhat prepared when you face this problems.
[edit]
To make my answer more clear I'll add a couple of examples.
To get the plugin name you can use:
extern "C" const char * plugin_name() {
return "Example plugin name";
}
// main.cc:
void* handle = dlopen("libplugin.so", RTLD_LAZY);
// ...
typedef const char * (*plugin_t)();
plugin_t call_plugin_name = (plugin_t) dlsym(handle, "plugin_name");
// ...
std::string my_plugin_name(call_plugin_name());
// use it
To really use the plugin functionality you should declare a base class in a header:
// plugin.h
class Plugin {
public:
virtual void doStuff() = 0;
virtual ~Plugin() = 0;
};
// plugin.cc
Plugin::~Plugin() {
}
// myplugin.cc
class MyPlugin : public Plugin {
virtual void doStuff() {
std::cout << "Hello from plugin" << std::endl;
}
};
extern "C" Plugin *createMyPluginInstance() {
return new MyPlugin;
}
Try:
extern "C" void plugin_name(std::string **name) {
*name = new std::string("Example plugin name");
}
...
std::string *my_plugin_name;
call_plugin_name(&my_plugin_name);
As you are assigning a copy of the pointer you passed as the argument, not the one you intended to assign.
EDIT Here you go:
File main.cpp
#include <iostream>
#include <dlfcn.h>
#include <string>
// Application.cpp
int main() {
void* handle = dlopen("libplugin.so", RTLD_LAZY);
typedef void (*plugin_t)(std::string**);
dlerror(); // Reset errors.
plugin_t call_plugin_name = (plugin_t) dlsym(handle, "plugin_name");
// ... Some error handling code.
std::string *my_plugin_name;
call_plugin_name(&my_plugin_name);
dlclose(handle);
// More code that displays my_plugin_name.
std::cout << "Plugin name is " << *my_plugin_name << std::endl;
delete my_plugin_name;
return 0;
}
File plugin.cpp
#include <string>
extern "C" void plugin_name(std::string **name) {
*name = new std::string("example plugin name");
}
Just a word of warning. Although this compiles and runs, passing C++ types across the dll boundry is risky and the above code is just your code fixed enough to compile and run, it is not safe and has very explicit memory handling. You may want to attack the problem in a different way.
Please have a read of this question and its answers. There are many opportunities for incompatibilities across the shared lib boundaries in C++.