I know there are many questions related to shared libraries on Linux but maybe because I'm tired of having a hard day trying to create a simple dynamic library on Linux (on Windows it would have taken less than 10 minutes) I can't find what happens in this case.
So, I am trying to create a library to be linked at build-time and used at run-time (not a static library, not a library to be embedded into the executable, in other words). For now it contains a simple function. These are my files:
1.
// gugulibrary.cpp
// This is where my function is doing its job
#include "gugulibrary.h"
namespace GuGu {
void SayHello() {
puts("Hello!");
}
}
2.
// gugulibrary.h
// This is where I declare my shared functions
#include <stdio.h>
namespace Gugu {
void SayHello();
}
3.
// guguapp.cpp
// This is the executable using the library
#include "gugulibrary.h"
int main() {
GuGu::SayHello();
return 0;
}
This is how I try to build my project (and I think this is what is wrong):
gcc -Wall -s -O2 -fPIC -c gugulibrary.cpp -o gugulibrary.o
ld -shared -o bin/libGugu.so gugulibrary.o
gcc -Wall -s -O2 guguapp.cpp -o bin/GuGu -ldl
export LD_LIBRARY_PATH=bin
This is saved as a .sh file which I click and execute in a terminal. The error I get when trying to link the library is this:
/tmp/ccG05CQD.o: In function `main':
guguapp.cpp:(.text.startup+0x7): undefined reference to `SayHello'
collect2: ld returned 1 exit status
And this is where I am lost. I want the library to sit in the same folder as the executable for now and maybe I need some symbols/definitions file or something, which I don't know how to create.
Thanks for your help!
In your C++ file, GuGu::SayHello is declared as a C++ symbol. In your header, you are wrapping it in an extern "C" block. This is actually undefined, as you aren't allowed to use C++ syntax (namespace) in that context. But my guess is that what the compiler is doing is ignoring the namespace and generating a C symbol name of "SayHello". Obviously such a function was never defined by your library. Take out the extern "C" bits, because your API as defined cannot be used from C anyway.
You are inconsistent with your GuGu, there are also Gugu's running around, this needs to be made consistent, then it works (At least on my computer are some Gugu's now)
Related
I have this simple code:
max = (int) sqrt (number);
and in the header I have:
#include <math.h>
But application still says undefined reference to sqrt. Do you see any problem here? It looks like everything should be okay.
You may find that you have to link with the math libraries on whatever system you're using, something like:
gcc -o myprog myprog.c -L/path/to/libs -lm
^^^ - this bit here.
Including headers lets a compiler know about function declarations but it does not necessarily automatically link to the code required to perform that function.
Failing that, you'll need to show us your code, your compile command and the platform you're running on (operating system, compiler, etc).
The following code compiles and links fine:
#include <math.h>
int main (void) {
int max = sqrt (9);
return 0;
}
Just be aware that some compilation systems depend on the order in which libraries are given on the command line. By that, I mean they may process the libraries in sequence and only use them to satisfy unresolved symbols at that point in the sequence.
So, for example, given the commands:
gcc -o plugh plugh.o -lxyzzy
gcc -o plugh -lxyzzy plugh.o
and plugh.o requires something from the xyzzy library, the second may not work as you expect. At the point where you list the library, there are no unresolved symbols to satisfy.
And when the unresolved symbols from plugh.o do appear, it's too late.
I suppose you have imported math.h with #include <math.h>
So the only other reason I can see is a missing linking information. You must link your code with the -lm option.
If you're simply trying to compile one file with gcc, just add -lm to your command line, otherwise, give some informations about your building process.
Just adding the #include <math.h> in c source file and -lm in Makefile at the end will work for me.
gcc -pthread -o p3 p3.c -lm
Here are my observation, firstly you need to include the header math.h as sqrt() function declared in math.h header file. For e.g
#include <math.h>
secondly, if you read manual page of sqrt you will notice this line Link with -lm.
#include <math.h> /* header file you need to include */
double sqrt(double x); /* prototype of sqrt() function */
Link with -lm. /* Library linking instruction */
But application still says undefined reference to sqrt. Do you see any
problem here?
Compiler error is correct as you haven't linked your program with library lm & linker is unable to find reference of sqrt(), you need to link it explicitly. For e.g
gcc -Wall -Wextra -Werror -pedantic test.c -lm
I had the same issue, but I simply solved it by adding -lm after the command that runs my code.
Example.
gcc code.c -lm
I'm not a frequent user of Linux and I think I did something wrong.
This is the code for a test dynamic library ".so" I'm generating.
class InternalClass
{
public:
int Function(){ return 10; }
};
extern "C"
{
int WrapperFunctionSimple() { return 10; }
void WrapperCreateInstance() {InternalClass* item = new InternalClass(); delete item; }
}
The compilation fails with the following error:
g++ -Wall -fexceptions -O2 -c /home/lidia/compartida/TestLibrary/TestLibrary/main.cpp -o obj/Release/main.o
g++ -shared obj/Release/main.o -o bin/Release/libTestLibrary.so -s
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: obj/Release/main.o: warning: relocation against `_Znwm##GLIBCXX_3.4' in read-only section `.text'
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: obj/Release/main.o: relocation R_X86_64_PC32 against symbol `_Znwm##GLIBCXX_3.4' can not be used when making a shared object; recompile with -fPIC
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
I tried with -fPIC as suggested and it compiles. But when using this library, It cannot be loaded when I add that last function:
void WrapperCreateInstance() {InternalClass* item = new InternalClass(); delete item; }
The problem is using the InternalClass, without this function everything works.
I'm using VirtualBox. I installed OpenSUSE 64bit, the app that uses the library is also 64bit. In another linux distribution (Mint), with exactly the same project and settings (without fPIC), it can be compiled. When I use that library (.so) it works in SUSE.
I'm also using :
gcc (SUSE Linux) 7.5.0
g++ (SUSE Linux) 7.5.0
My IDE is Code::Blocks 20 (last version). Settings are empty except for the -m64 flag.
What am I doing wrong? This seems like something advanced Linux users could help me understand.
EDIT:
To add more information, this can compile in Ubuntu with the same settings. Not in SUSE
To me it happened, if one library (A) depends on another one (B) and library A was linked before library B. The solution is to link library B first and then A.
It happened to me when I used GCC to compile a CPP file. So for C++ files use g++ only, and obviously not GCC, which is meant for c files.
I am using cmake and GCC in ubuntu and I got the same error.
In my case, I added the XX.h file to include directories, and used in my main.cpp a "typedef struct x" which is defined in XX.h header file. However I forgot to add XX.c to the executable sources.
This error is cleared when I added XX.c to the target executable sources in add_executable() of Cmake.
I hope I can clearly state my case.
In my case this happened when I had an abstract class A and two derived classes B and C like below.
class BaseAbstractClass
{
public:
virtual void doNothing(void) = 0;
};
class A : public BaseAbstractClass
{
public:
void doNothing(void){
return;
}
};
class B : public BaseAbstractClass
{
public:
void doNothing(void); // Only declaration, definition is nowhere
};
But one of derived classes (class B here) has only declaration of doNothing(), but lacks definition anywhere in project files.
I had a similar issue and the order of linking answer was useful for me. It ended up being I was including the cpp file rather than the header (include was called at wrong time.)
There's a C++ code:
#include <stdio.h>
int main() {
int b = sizeof('a');
if(b==4) printf("I'm a C program!\n");
else printf("I'm a C++ program!\n");
}
Compile it like this:
gcc main.cpp -o main
It succeeds and gives:
I'm a C++ program!
Then add a line somewhere inside function main
int *p1 = new int [1000];
It fails with:
C:\Users\...\AppData\Local\Temp\cccJZ8kN.o:main1.cpp:(.text+0x1f): undefined reference to operator new[](unsigned long long)'
collect2.exe: error: ld returned 1 exit status
Then the following two commands successfully compile the code:
gcc main.cpp -o main -lstdc++
and
g++ main.cpp -o main
The compiler is minGW-win64 (http://mingw-w64.sourceforge.net/).
The questions are:
Which of the two last commands are better?
To my mind gcc correctly chooses the right compiler but then uses a wrong linker. Is it right?
May it be a problem in minGW-win64?
As I see (correct me if it's wrong) gcc was intended to be a main program that takes the input and decides what to do with it. So I'd better use gcc if it worked without -lstdc++. But if it's not possible I'll prefer using g++ instead as don't know what else gcc may miss.
Many thanks for your considerations
gcc is the GCC compiler-driver for C programs, g++ is the one for C++ programs.
Both will guess the language on the basis of the file-extension, unless overridden.
But if you use the wrong driver, the default-options will be wrong, like leaving out the C++ standard-library for C++ programs compiled with gcc when linking.
You can add just the library with -lstdc++, though using the proper driver is preferable, as plain gcc may be missing other, subtler options.
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 5 years ago.
I'm getting an "undefined reference" error when trying to compile and link a very simple app that has a dependency on a third-party library.
My main.c looks like this:
#include "ss7cp.h"
/*
extern "C" {
void EINSS7CpMain_CpInit(void);
}
*/
int main() {
EINSS7CpMain_CpInit();
}
The third-party header file has:
#if defined (__cplusplus) || defined (c_plusplus)
extern "C" {
#endif
...
void EINSS7CpMain_CpInit(void);
The definition of this function is in an archive:
$ nm -g /path/to/lib/libsign_64_uthr.a | grep EINSS7CpMain_CpInit
0000000000005ae0 T EINSS7CpMain_CpInit
U EINSS7CpMain_CpInit
U EINSS7CpMain_CpInit
By the "T" above, the function must be defined in the text/code section of one of the libs in the archive.
I'm currently not using a Makefile, but just trying to quickly build this simple app entirely from the command line:
g++ -I/path/to/include -L/path/to/lib -lsign_64_uthr -D__EXTENSIONS__ -DLINUX main.c
(The documentation told me to define both __EXTENSIONS__ and LINUX). The rest of the above is pretty straightforward. What I'm getting is:
/tmp/ccvgmIJ8.o: In function `main':
main.c:(.text+0x5): undefined reference to `EINSS7CpMain_CpInit'
collect2: error: ld returned 1 exit status
I've tried both as a C file (main.c) and C++ file (main.cpp, enabling the extern "C" block), but no difference. (Can I assume g++ decides on C versus C++ just by the file extension?)
I've even just compiled the file (with -c) and took a look at the contents of the resultant main.o object file and saw the text "EINSS7CpMain_CpInit" as it is, unmangled (or maybe that's just a debug symbol?)
What are some diagnostics steps I can take to see what I'm missing? Do I actually need to create a Makefile and split the compile and link steps?
It's been ages since I last did any C/C++ and even back when I did it, I usually wasn't the one who had to create the Makefiles from scratch, so I'm probably missing some very fundamental stuff here...
My best guess would be parameter ordering, the lib should come after the source file:
g++ -I/path/to/include -D__EXTENSIONS__ -DLINUX main.c -L/path/to/lib -lsign_64_uthr
I want to use the VLFeat Libaries in C from a C++ file. Their tutorial for g++ presents a basic "Hello World" example which is compiled as follows:
g++ main.cpp -o vlfeat-test -I /disk/no_backup/lesi/vlfeat-0.9.20/ -L /disk/no_backup/lesi/vlfeat-0.9.20/bin/glnxa64/ -lvl
This works fine. What I want now is to add the library to my .bashrc, so I don't need the extra flags:
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/disk/no_backup/lesi/vlfeat-0.9.20
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/disk/no_backup/lesi/vlfeat-0.9.20/bin/glnxa64
and use it like this:
g++ main.cpp -o vlfeat-test
Unfortunately I get the following error:
/tmp/cc6tzB55.o: In function `main':
main.cpp:(.text+0x10): undefined reference to `vl_get_printf_func'
collect2: error: ld returned 1 exit status
What am I doing wrong?
Here's the "Hello World" code from the tutorial:
extern "C" {
#include <vl/generic.h>
}
int main (int argc, const char * argv[]) {
VL_PRINT ("Hello world!\n") ;
return 0;
}
VLFeat Library Link: http://www.vlfeat.org/index.html
You specify where to find the header, but you don't tell the compiler to link against the library.
There is no magic mapping from "this C file included this header" to "I better link this program with this library", it doesn't work like that.
I could make a library with a single unwind-mess.h header, that declares functions implemented in three different library files, and call the libraries libcream.a, libmeringue.a and libberry.a.
You still need the -lvl option to tell the compiler there's extra library code that needs to be linked against.