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.
Related
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.
I am working on a school project which requires to work with sheepdog. Sheepdog provides a c api which enables you to connect to a sheepdog server.
First i create c source file(test.c) with the following content :
#include "sheepdog/sheepdog.h"
#include <stdio.h>
int main()
{
struct sd_cluster *c = sd_connect("192.168.1.104:7000");
if (!c) {
fprintf(stderr, "failed to connect %m\n");
return -1;
}else{
fprintf(stderr, "connected successfully %m\n");
}
return 0;
}
then i compile with no error using the following command
gcc -o test test.c -lsheepdog -lpthread
But what i need is to use it with c++ project so i created a cpp file(test.cpp) with the following content :
extern "C"{
#include "sheepdog/sheepdog.h"
}
#include <stdio.h>
int main()
{
struct sd_cluster *c = sd_connect("192.168.1.104:7000");
if (!c) {
fprintf(stderr, "failed to connect %m\n");
return -1;
}else{
fprintf(stderr, "connected successfully %m\n");
}
return 0;
}
now, when i compiled using the following command :
g++ -o test test.cpp -lsheepdog -lpthread
I got this error :
You can't just wrap extern "C" around a header and expect it to compile in a C++ program. For example, the header sheepdog_proto.h uses an argument named new; that's a keyword in C++, so there's no way that will compile as C++. The library was not designed to be called from C++.
I agree with #PeteBecker. From a quick look around Google, I am not sure there is an easy solution. Sheepdog is using C features and names that don't port well to C++. You might need to hack sheepdog fairly extensively. For example:
move the inline functions out of sheepdog_proto.h into a new C file, leaving prototypes in their place. This should take care of the offsetof errors, e.g., discussed in this answer.
#define new not_a_keyword_new in sheepdog/sheepdog.h
and whatever other specific changes you have to make to get it to compile. More advice from the experts here.
As sheepdog was not designed to be useable from C++ you should build a tiny wrapper in C language to call the functions from sheepdog and only call the wrapper from your c++ code. Some hints to write such a wrapper:
void * is great to pass opaque pointers
extractors can help to access badly named members. If a struct has a member called new (of type T), you could write:
T getNew(void *otherstruct); // declaration in .h
and
T getNew(void *otherstruct) { // implementation in a c file
return ((ActualStruct *) otherstruct)->new;
}
Depending on the complexity of sheepdog (I do not know it) and the part you want to use, it may or not be an acceptable solution. But it is the way I would try facing such a problem.
Anyway, the linker allows mixing modules compiled in C and in C++, either in static linking or dynamic linking.
I have a program written in C and I need to use KDIS libraries which are written in C++. I compile my C program with automake&friends in KDevelop. How can I compile everything together?? Because I want to call some KDIS functions inside my C program.
Thank you in advance.
If you need to call C++ functions which are not declated extern "C", then you have to do so from a C++ program yourself. You can create one single C++ file in your project which wraps all the library functions you need in extern "C" functions to be used by the rest of your project. You'll have to tell autotools that you're using both C and C++. The file extensions should be enough to decide which is which.
To give you an example, consider the following mymagic.cc creating bindings for some libmagic written in C++:
#include <libmagic/magic.hh>
extern "C" {
int doMagic() {
magic::Wizard w("foo", 42);
magic::Result res = w.doMagic();
return res.getResultCode();
}
}
To the rest of your application, doMagic() would appear as just another C function. But the inside is C++, so it can use any C++ constructs you want. When you need to pass stuff from your library around, you should use pointers to opaque types. So in the header mymagic.h which is also used by your C code, you can write
struct magicValue;
int doMagic(void);
struct magicValue* createMagic(void);
void destroyMagic(struct magicValue*);
And in the mymagic.cc you'd then be more explicit:
struct magicValue {
magic::value v;
magicValue(magic::value val) : v(val) { }
};
magicValue* createMagic() {
return new magicValue(magic::value("foo"));
}
void destroyMagic(magicValue*) {
delete magicValue;
}
This link may help you understand how to mix C and C++ code in your application.
Also, look at this Stack Overflow question, I believe that's what you need.
A few days back, I came across this piece of C++ code, though I can't paste the code itself, I could recreate the problem with some sample code.
First, the file, namespace.h:
#include <iostream>
using namespace std;
namespace useless{
class X {
int m_myint;
static X *m_foobar;
X* getPrivVal(void);
public:
int getMember(void);
X* getStaticVal(void);
};
}
Next, namespace.cpp:
#include "namespace.h"
extern "C"{
namespace useless{
X* X::m_foobar = NULL;
X* X::getPrivVal(void){
if(m_foobar == NULL)
m_foobar = new X;
return(m_foobar);
}
}
}
namespace useless {
int X::getMember(void){
if(m_myint == 0)
m_myint = 1;
return(m_myint);
}
X* X::getStaticVal(void){
return(getPrivVal());
}
}
using namespace useless;
int main(void){
X y;
cout << "The int value is " << y.getMember() << endl;
cout << "The value of the static member is " << y.getStaticVal() << endl;
return(0);
}
This code compiled and linked fine when I used g++ 3.4.3, but gives the following error when I use g++ 4.x, I have tried with GCC 4.6.1 as well GCC 4.2.1. Have tried it on Linux as well as Mac, same results.
This is the error(Suse):
g++ -o namespace namespace.cpp
namespace.h:8:15: error: previous declaration of useless::X*
useless::X::m_foobar with C++ linkage
namespace.cpp:5:11: error: conflicts with new declaration with C linkage
Can someone please shed some light on what the legacy C++ code was looking to do, could this have been a hack or workaround to get around an old problem that I am not aware of any longer. Ohh by the way, the method inside the extern "C" is called by C++ code and not any C code as I initially suspected.
FYI, this is legacy code now, may have been written in 2001/2002 period.
Thanks guys. I have gone ahead and got rid of the extern "C" with no major impact.
#Bjorn Pollex : The guy who wrote that code is long gone.
The extern "C" directive has two effects, it disables mangling when possible and uses the C calling convention. In this particular case, because there is a namespace in between, name mangling cannot be disabled, so it could have been added to force a particular calling convention.
The code is actually wrong in that the declaration does not force extern "C" but the definition does, which is incorrect. Consider that if the compiler just followed the directive as shown, the caller would use C++ naming and calling conventions, while the function would be using the C variant, if the two differ the result will be undefined behavior.
Seems like an attempt to generate the variables witout C++ name mangling. That's one part of using extern "C".
The newer compiler obviously realizes that it really doesn't work.
If you have a piece of C++ code that you want to call from a module written in another language (C, FORTRAN or whatever), you want to turn off C++ name mangling.
Edit:
The really weird thing is that they did it on the definition but not on the declaration. It's a wonder that it ever compiled
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++.