I'm trying to get a simple c++ program to use a method in a dll. I've been receiving a variety of errors as I've adjusted the code and have been stuck mostly, as in the code posted below, with "undefined reference to" the method. The code below is being compiled as follows.
g++ -c testdll.cpp
g++ -shared -o testdll.dll testdll.o
g++ -o test test.cpp -L./ -ltestdll
error
g++ -o test test.cpp -L./ -ltestdll
C:\Users\ROGERF~1\AppData\Local\Temp\cca9YhFn.o:test.cpp:(.text+0x53): undefined
reference to `__imp__ZN7TestDLL9writeDataESs'
collect2.exe: error: ld returned 1 exit status
I have no idea why directory C:\Users\ROGERF~1\AppData\Local\Temp\ is involved in the process. That showed up after I started using code from the Microsoft website in the header file. Previously, I was just getting undefined reference to 'writeData'
testdll.cpp
#include <stdio.h>
#include <string>
using namespace std;
class TestDLL {
public:
string data1;
public: void writeData (string s) {
printf ("%s \n", s.c_str());
}
};
TestDLL.h
#ifndef TESTDLL_H
#define TESTDLL_H
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
class TestDLL {
public:
std::string data1;
public:
TRADITIONALDLL_API void writeData (std::string);
};
#ifdef __cplusplus
}
#endif
#endif // TESTDLL_H
test.cpp
#include <string>
#include "TestDLL.h"
using namespace std;
class TestDLL;
int
main () {
TestDLL testdll;
testdll.writeData ("success");
}
Extended explanation: I've focused this down to something easy to post and hopefully easy for someone to answer. I was a C programmer back at the dawn of the PC era but haven't done much with C++ ever or C since then. I've been a Java programmer for quite some time (along with web stuff). Right now, I'm dealing with an existing program that can be extended with dlls, and the dlls need to be connected to a system written in Java. I've done the first step in JNI, so I have Java connected to a single dll. But the architecture needs to be:
Existing C application - dll extensions - dll for JNI - Java system
with communication both ways.
What happens if you add the two following lines to testdll.cpp:
#define TRADITIONALDLL_EXPORTS 1
#include "TestDLL.h"
I suspect that what's happening is that you're not doing that, so GCC doesn't know to compile TestDLL::writeData() with DLL export linkage.
Related
In my Eclipse C/C++ project there is this undefined reference error which doesn't go away, doesn't matter what I do. I already changed the link order, checked if all files are compiled and included, basically everything, which is recommended in the in the Internet, when facing this problem.
Here's my program:
[...] - means that there is more code, which doesn't relate.
menulib.h
[...]
void start_GUI( void );
[...]
start_GUI.c - Note this is a .c-File
#include "menulib.h"
void start_GUI( void )
{
[...]
}
coreInterface.h
#ifndef COREINTERFACE_H_
#define COREINTERFACE_H_
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
/** only include the Core when compiled for C++ */
#include "Core.h"
#endif /* #ifdef CORE */
#ifdef __cplusplus
extern "C" {
#endif
void init_GUI( Core* core);
#ifdef __cplusplus
}
#endif
#endif /* COREINTERFACE_H_ */
coreInterface.cpp - Note this is a .cpp-File
#include "coreInterface.h"
#include "menulib.h"
void init_GUI( Core* core)
{
gui_core = core;
start_GUI(); // <--- **error appears here** - calls a .c file
}
Here's the error in the makefile (the auto generated one from Eclipse):
g++ -L/home/PC/the_Project/menu_GUI -o "the_Project" [...] ./menu_GUI/coreInterface.o [...] ./menu_GUI/start_GUI.o [...] -lcurses
./menu_GUI/coreInterface.o: In function `init_GUI':
/home/PC/the_Project/Default/../menu_GUI/coreInterface.cpp:23: undefined reference to `start_GUI()'
I believe this is coming from merging the .c and .cpp files. Still I couldn't solve it. Has anyone an idea?
Kind Regards
The problem is that you share the menulib.h header between C and C++ without specifying to C++ compiler that the function start_GUI is defined in C. Use extern "C" in #ifdef not only for init_GUI, but also for start_GUI.
Working example:
#include "coreInterface.h"
extern "C" {
#include "menulib.h"
}
void init_GUI( Core* core)
{
gui_core = core;
start_GUI();
}
I tried to link a static library (compiled with gcc) to a c++ program and I got 'undefined reference'. I used gcc and g++ version 4.6.3 on a ubuntu 12.04 server machine. For example, here is the simple library file for factorial method:
mylib.h
#ifndef __MYLIB_H_
#define __MYLIB_H_
int factorial(int n);
#endif
mylib.c
#include "mylib.h"
int factorial(int n)
{
return ((n>=1)?(n*factorial(n-1)):1);
}
I created object for this mylib.c using gcc:
gcc -o mylib.o -c mylib.c
Again the static library was created from the object file using AR utility:
ar -cvq libfact.a mylib.o
I tested this library with a C program (test.c) and C++ program (test.cpp)
Both C and C++ program have the same body:
#include "mylib.h"
int main()
{
int fact = factorial(5);
return 0;
}
Assuming static library libfact.a is available in /home/test directory, I compiled my C program without any issues:
gcc test.c -L/home/test -lfact
However while testing C++ program, it threw a link error:
g++ test.cpp -L/home/test -lfact
test.cpp:(.text+0x2f): undefined reference to `factorial(int)'
collect2: ld returned 1 exit status
I even tried adding extern command in test.cpp:
extern int factorial(int n) //added just before the main () function
Still the same error.
Can someone tell me what I am wrong here?
Is there anything I missed while creating the static library?
Do I have to add anything in my test.cpp to make it work?
The problem is that you haven't told your C++ program that factorial is written in C. You need to change your test.h header file. Like this
#ifndef __MYLIB_H_
#define __MYLIB_H_
#ifdef __cplusplus
extern "C" {
#endif
int factorial(int n);
#ifdef __cplusplus
}
#endif
#endif
Now your header file should work for both C and C++ programs. See here for details.
BTW names containing a double underscore are reserved for the compliler (so are names starting with an underscore and a capital letter) so #ifndef __MYLIB_H_ is illegal strictly speaking. I would change to #ifndef MYLIB_H #define MYLIB_H
While the accepted answer is absolutely correct, I thought I'd just add an observation. Some editors have trouble with the open / close brace, and will indent the entire extern "C" scope in the header. If mylib.h is a key header for a library, you might consider:
#if defined (__cplusplus)
#define _MYLIB_INIT_DECL extern "C" {
#define _MYLIB_FINI_DECL }
#else
#define _MYLIB_INIT_DECL
#define _MYLIB_FINI_DECL
#endif
All other headers in mylib library, e.g., mylib_aux.h, can be of the form:
#ifndef _MYLIB_AUX_H
#define _MYLIB_AUX_H
#include <mylib.h>
_MYLIB_INIT_DECL
... header content ...
_MYLIB_FINI_DECL
#endif /* _MYLIB_AUX_H */
Obviously, the names I'm using are arbitrary, but for multiple library headers, this approach has been useful to me.
I have a C function that I would like to call from C++. I couldn't use "extern "C" void foo()" kind of approach because the C function failed to be compiled using g++. But it compiles fine using gcc. Any ideas how to call the function from C++?
Compile the C code like this:
gcc -c -o somecode.o somecode.c
Then the C++ code like this:
g++ -c -o othercode.o othercode.cpp
Then link them together, with the C++ linker:
g++ -o yourprogram somecode.o othercode.o
You also have to tell the C++ compiler a C header is coming when you include the declaration for the C function. So othercode.cpp begins with:
extern "C" {
#include "somecode.h"
}
somecode.h should contain something like:
#ifndef SOMECODE_H_
#define SOMECODE_H_
void foo();
#endif
(I used gcc in this example, but the principle is the same for any compiler. Build separately as C and C++, respectively, then link it together.)
Let me gather the bits and pieces from the other answers and comments, to give you an example with cleanly separated C and C++ code:
The C Part:
foo.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c
#include "foo.h"
void foo(void)
{
/* ... */
}
Compile this with gcc -c -o foo.o foo.c.
The C++ Part:
bar.cpp
extern "C" {
#include "foo.h" //a C header, so wrap it in extern "C"
}
void bar() {
foo();
}
Compile this with g++ -c -o bar.o bar.cpp
And then link it all together:
g++ -o myfoobar foo.o bar.o
Rationale:
The C code should be plain C code, no #ifdefs for "maybe someday I'll call this from another language". If some C++ programmer calls your C functions, it's their problem how to do that, not yours. And if you are the C++ programmer, then the C header might not be yours and you should not change it, so the handling of unmangled function names (i.e. the extern "C") belongs in your C++ code.
You might, of course, write yourself a convenience C++ header that does nothing except wrapping the C header into an extern "C" declaration.
I agree with Prof. Falken's answer, but after Arne Mertz's comment I want to give a complete example (the most important part is the #ifdef __cplusplus):
somecode.h
#ifndef H_SOMECODE
#define H_SOMECODE
#ifdef __cplusplus
extern "C" {
#endif
void foo(void);
#ifdef __cplusplus
}
#endif
#endif /* H_SOMECODE */
somecode.c
#include "somecode.h"
void foo(void)
{
/* ... */
}
othercode.hpp
#ifndef HPP_OTHERCODE
#define HPP_OTHERCODE
void bar();
#endif /* HPP_OTHERCODE */
othercode.cpp
#include "othercode.hpp"
#include "somecode.h"
void bar()
{
foo(); // call C function
// ...
}
Then you follow Prof. Falken's instructions to compile and link.
This works because when compiling with gcc, the macro __cplusplus is not defined, so the header somecode.h included in somecode.c is like this after preprocessing:
void foo(void);
and when compiling with g++, then __cplusplus is defined, and so the header included in othercode.cpp is now like that:
extern "C" {
void foo(void);
}
This answer is inspired by a case where Arne's rationale was correct. A vendor wrote a library which once supported both C and C++; however, the latest version only supported C. The following vestigial directives left in the code were misleading:
#ifdef __cplusplus
extern "C" {
#endif
This cost me several hours trying to compile in C++. Simply calling C from C++ was much easier.
The ifdef __cplusplus convention is in violation of the single responsibility principle. A code using this convention is trying to do two things at once:
(1) execute a function in C
-- and --
(2) execute the same function in C++
It's like trying to write in both American and British English at the same time. This is unnecessarily throwing an #ifdef __thequeensenglish spanner #elif __yankeeenglish wrench #else a useless tool which makes the code harder to read #endif into the code.
For simple code and small libraries the ifdef __cplusplus convention may work; however, for complex libraries it is best to pick one language or the other and stick with it. Supporting one of the languages will take less maintenance than trying to support both.
This is a record of the modifications I made to Arne's code to get it to compile on Ubuntu Linux.
foo.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c
#include "foo.h"
#include <stdio.h>
void foo(void)
{
// modified to verify the code was called
printf("This Hello World was called in C++ and written in C\n");
}
bar.cpp
extern "C" {
#include "foo.h" //a C header, so wrap it in extern "C"
}
int main() {
foo();
return(0);
}
Makefile
# -*- MakeFile -*-
# dont forget to use tabs, not spaces for indents
# to use simple copy this file in the same directory and type 'make'
myfoobar: bar.o foo.o
g++ -o myfoobar foo.o bar.o
bar.o: bar.cpp
g++ -c -o bar.o bar.cpp
foo.o: foo.c
gcc -c -o foo.o foo.c
I've created some simple basic code to illustrate my problem.
header.h:
#ifdef __cplusplus
# define API extern "C"
#else
# define API
#endif
void callback();
API void libFunction();
testlib.c:
#include "header.h"
void libFunction()
{
Callback();
}
I compile this as a static library like so:
gcc -c testlib.c
ar rsc libtest.a testlib.o
Then my sample c++ code is
main.cpp:
extern "C"{
#include <lib/header.h>
}
#include <stdio.h>
main()
{
libFunction();
}
void Callback()
{
printf("Callback is called \n");
}
and I try to build my exe as so
g++ -I. -L. main.cpp -ltest
and get the following error
./lib/libtest.a(testlib.o): In function `libFunction':
testlib.c:(.text+0x7): undefined reference to `Callback'
collect2: ld returned 1 exit status
I have spent literally all day trying to figure out why. Can anyone please help?
If you want to call Callback from a C file, it needs to be built extern "C" in your C++ file - otherwise C++ name mangling will cause the symbols to not line up. You need to change the definition of Callback() in main.cpp to be:
extern "C" void Callback()
You have a case mismatch, too. The prototype in your header says callback, but everywhere else you use Callback. On re-reading your code, I think just fixing this case mismatch will solve all your problems. I didn't see the extern "C" wrapper around the #include <lib/header.h> on first reading.
I have a problem. I wrote example code and I want to build it without the error:
main.cpp(.text+0x5): undefined reference to `test()'
Library
test1.c
#include <stdlib.h>
void test()
{
puts("DziaĆa");
}
test1.h
#ifndef TEST1_H
#define TEST1_H
extern void test();
#endif
makefile
all:
gcc -c ./src/test1.c -o ./lib/test1.o
ar rcs ./lib/libtest1.a ./lib/test1.o
Program
main.cpp
#include <test1.h>
int main()
{
test();
return 0;
}
makefile
all:
g++ -static -I../test1/include -L../test1/lib ./src/main.cpp -o ./build/MyApp -ltest1
What am I doing wrong?
You are compiling a C code function, but you are expecting to link a C++ function.
Because of 'type safe linkage', the function you provide is not the function that the C++ code calls.
Either in test1.h use:
#ifdef __cplusplus
extern "C" {
#endif
extern void test1(void);
#ifdef __cplusplus
}
#endif
Or:
Compile the function with the C++ compiler.
The C++ compiler will mangle the symbol names to provide type-safe linkage (a term which you should be able to search for via your preferred search engine).
The 'compiler' - actually the linker - is looking for a function with a C++ mangled name representing the C++ function with the signature 'void test1(void);'.
For example (but remember - different compilers deliberately mangle things differently), G++ 4.2.1 on MacOS X 10.6.2 generates a symbol '__Z5test1v' for the function; GCC generates a symbol '_test1'. Clearly, when the linker is looking for '__Z5test1v', the symbol '_test1' is not going to be used - it is not spelled the same. This is a good thing.
You can use 'nm -g' on the object file for the main program to see what it is looking for, and on the object file in the library to see what it is providing. And, given that the spellings are different, that is why the loader does not pick up the library function - it is looking for something with a different name.
You are calling a C function from a C++ function. The naming between the two is different (C++ mangles names to include parameter information).
Change the header file to look like this:
#ifdef __cplusplus
extern "C" {
#endif
extern void test();
#ifdef __cplusplus
}
#endif
This will tell the compiler that the function follows the C naming/calling convention.