ar introduces undefined reference - linker

I'm trying to figure out how to use static libraries, but the most trivial example fails:
//foo.c
int func(int i) {
return i+1;
}
//main.c
int func(int i);
int main() {
return func(41);
}
Compiling foo.c and main.c works:
gcc -Wall -o foo.o -c foo.c
gcc -Wall -o main.o -c main.c
Archiving foo.o does not complain either:
ar rcs libfoo.a foo.o
But Linking fails with an undefined reference to func:
ld libfoo.a main.o
ld -L. -lfoo main.o
both give me:
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
main.o: In function `main':
main.c:(.text+0xa): undefined reference to `func'
I get a similar error if I take the detour via gcc to link:
gcc libfoo.a main.o
gcc -L. -lfoo main.o
give me:
main.o: In function `main':
main.c:(.text+0xa): undefined reference to `func'
collect2: ld returned 1 exit status
What am I doing wrong here? According to all manuals and search engines I read/used this is the way to use static libraries.
Edit: Mind that gcc foo.o main.o works perfectly fine.

After a lot of trying stupid stuff, the most stupid idea was the solution: ld wants the object files first, then the archives. Yay!
gcc libfoo.a main.o // fails
gcc main.o libfoo.a // works
The same goes if you specify the library with -L. and -lfoo: Where you put -L doesn't matter apparently, but where you put -lfoo matters to the same extent as if you specify the .a file directly.

Related

main.c:(.text+0x170): undefined reference to `sqrt' (used -lm)

ok, so i'm trying to compile my code using makefile, i've got only 2 .c file and 1 .h file, i used "sqrt()" function from math.h (only in main), here is my makefile:
a.out: GBST.o main.o
gcc GBST.o main.o
GBST.o: GBST.c GBST.h
gcc -c GBST.c
main.o: main.c
gcc -c main.c -lm
still, I get main.c:(.text+0x170): undefined reference to `sqrt' error, what can it be? (btw, i wrote -lm in GBST line before and it did not help, so i have deleted it)
You need to use -lm in the link line, not in the compile line.
a.out: GBST.o main.o
gcc GBST.o main.o -lm
# ^^^^ Need it here
GBST.o: GBST.c GBST.h
gcc -c GBST.c
main.o: main.c
gcc -c main.c
# ^^^^ Don't need it here

Makefile Linker unable to find functions in static library

sorry for this question that may seem trivial, but I looked at a few tutorials and SO questions and still could not figure out what is wrong.
Anyway, when using gcc, the linker is not able to find functions in the static library I have included.
Error message:
arm-none-linux-gnueabi-gcc -I. -I./include yuv.c -c -o yuv.o
arm-none-linux-gnueabi-gcc -I. -I./include main.c -c -o main.o
arm-none-linux-gnueabi-gcc -L./lib -I. -I./include yuv.o main.o -lpthread -lrt -ljpeg -o grab.elf
main.o: In function `jpegWrite':
main.c:(.text+0x118): undefined reference to `jpeg_std_error'
main.c:(.text+0x134): undefined reference to `jpeg_CreateCompress'
main.c:(.text+0x144): undefined reference to `jpeg_stdio_dest'
main.c:(.text+0x17c): undefined reference to `jpeg_set_defaults'
main.c:(.text+0x198): undefined reference to `jpeg_set_quality'
main.c:(.text+0x1a8): undefined reference to `jpeg_start_compress'
main.c:(.text+0x1e4): undefined reference to `jpeg_write_scanlines'
main.c:(.text+0x200): undefined reference to `jpeg_finish_compress'
main.c:(.text+0x20c): undefined reference to `jpeg_destroy_compress'
collect2: ld returned 1 exit status
make: *** [grab.elf] Error 1
My file structure is as follows:
Makefile
main.c
In Folder lib
libjpeg.a
My Makefile reads:
GCC=gcc
INC_PATH= -I. -I./include
LIBS_PATH = -L./lib
HEADER_FILE=./yuv.h ./include/jpeglib.h
grab.elf: yuv.o main.o
$(CROSS_COMPILE)$(GCC) $(LIBS_PATH) $(INC_PATH) yuv.o main.o -lpthread -lrt -ljpeg -o grab.elf
yuv.o:yuv.c $(HEADER_FILE)
$(CROSS_COMPILE)$(GCC) $(INC_PATH) yuv.c -c -o yuv.o
main.o:main.c $(HEADER_FILE)
$(CROSS_COMPILE)$(GCC) $(INC_PATH) main.c -c -o main.o
I also tried:
nm libjpeg.a | grep jpeg_std
000001f0 T _jpeg_stdio_dest
00000140 T _jpeg_stdio_src
000001f0 T _jpeg_std_error
000012c0 R _jpeg_std_message_table
Would any kind soul care to help me? Thank you.
Could it be that libjpeg.a was compiled on the platform on which you are developing, whereas the target of grab.elf is different? i.e., you are developing on x86 environment and targeting ARM?

How to compile this lib for usage?

I'm new to C programming, and I'm trying to compile this Simple training example with GCC on Ubuntu 12.10.
Looks like fann.h should not be included (as stated on the file itself), so I included fixedfann.h instead.
First attempt (without include, just to see what the compiler will ask for):
$ gcc main.c -o output
/tmp/cckKyM92.o: In function `main':
main.c:(.text+0x62): undefined reference to `fann_create_standard'
main.c:(.text+0x7a): undefined reference to `fann_set_activation_function_hidden'
main.c:(.text+0x8e): undefined reference to `fann_set_activation_function_output'
main.c:(.text+0xba): undefined reference to `fann_train_on_file'
main.c:(.text+0xce): undefined reference to `fann_save'
main.c:(.text+0xda): undefined reference to `fann_destroy'
collect2: ld returned 1 exit status
fann_create_standard is on fann.h and fann.c. As fann.h is included by fixedfann.h, and fann.h should not be included directly, I believe I have to compile fann.c and fixedfann.c, and link then (tell me if I'm doing any mistake, I'm still not familiar with this "linking" stuff).
So I did:
$ gcc fann/fixedfann.c -o fann/fixedfann.o
fann/fixedfann.c:22:20: fatal error: config.h: No such file or directory
compilation terminated.
and then I did:
$ gcc fann/fixedfann.c -o fann/fixedfann.o -include fann/include/config.h
fann/fixedfann.c:22:20: fatal error: config.h: No such file or directory
compilation terminated.
Now, why it's not finding the config.h file here?
--update
Thanks #JonathanLeffler, I could make some steps here. But now I'm stuck at:
$ gcc fann/fixedfann.c -o fann/fixedfann.o -I./fann/include/ -lm
/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: ld returned 1 exit status
and, with grep, I could not find any reference to main on the fann folder... Also no function _start, and I don't know who is linking this crt1.o... Any idea what's wrong here?
--update2
Ok, I got the .o files using Harmeet's Makefile, now I'm trying to link everything.
I created the main.o with gcc -c main.c, and I tried:
gcc -o output main.o fann/fixedfann.o -lm
(-lm for the libmath, that is needed) and I got:
main.c:(.text+0xba): undefined reference to `fann_train_on_file'
This fann_train_on_file is on fann_train_data.c, so I tried:
gcc -o output main.o fann/fixedfann.o fann/fann_train_data.o -lm
but I got lots of multiple definition of... errors... :/
Looks like fann_train_data.o is already included/linked, but if so, why it's not finding fann_train_on_file?
--update3
I'm still really stuck here... Any idea of which (if any) of this two lines should work?:
gcc -o output main.o hello.o fann/fixedfann.o fann/fann_train_data.o -lm
or
gcc -o output main.o hello.o fann/fixedfann.o -lm
--update for Harmeet
The output was:
$ make
gcc -L./fann -lfann main.o -o main
main.o: In function `main':
main.c:(.text+0x62): undefined reference to `fann_create_standard'
main.c:(.text+0x7a): undefined reference to `fann_set_activation_function_hidden'
main.c:(.text+0x8e): undefined reference to `fann_set_activation_function_output'
main.c:(.text+0xba): undefined reference to `fann_train_on_file'
main.c:(.text+0xce): undefined reference to `fann_save'
main.c:(.text+0xda): undefined reference to `fann_destroy'
collect2: ld returned 1 exit status
make: *** [main] Error 1
You can use ar to make a static library and work with that.
Create a Makefile under your hello-fann-3/fann/ folder with the following contents -
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
CFLAGS = -c -Iinclude
all: libfann.a
libfann.a: $(OBJECTS)
ar rcs $# $^
%.o: %.c
gcc $(CFLAGS) $^
Then use the make command in hello-fann-3/fann/ to build the static library. The above Makefile will generate libfann.a that you can link to your program.
Create a Makefile under your hello-fann-3/ folder with the following contents -
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
CFLAGS = -c -I./fann/include
LFLAGS = -L./fann -lfann
main: $(OBJECTS)
gcc $(LFLAGS) $^ -o $#
%.o: %.c
gcc $(CFLAGS) $^
Then use the make command in hello-fann-3/ to build the main program.
In your main.c, you must include fan.h like -
#include "fann.h"
If you do not understand the Makefile, you can read about it here -
http://www.gnu.org/software/make/manual/html_node/index.html
You just need to link the fann library.
If you compile manually do this
gcc main.c -lfann -lm -o main
then simply run it like
./main
If you are on Ubuntu and you faced the following error
./main: error while loading shared libraries: libfann.so.2: cannot open shared object file: No such file or directory
Then run
sudo ldconfig
If you are using NetBeans, then simply Right click on your project -> Properties -> Build -> Linker,
then in the Libraries section click on the browse button [...] then in the new window click on Add Library...
Then add fann library (for example my fann library path is: /usr/local/lib/libfann.a) and click Ok
A fellow helped me, and we came to this line that compiled everything, and make the executable:
$ gcc fann/fann.c fann/fann_io.c fann/fann_train.c fann/fann_train_data.c fann/fann_error.c fann/fann_cascade.c main.c -Ifann/include -lm
And this is the answer.
That said, this is exactly what fixedfann.c is doing (include all this .c files). But if I try:
$ gcc fann/fixedfann.c main.c -Ifann/include -lm
..I get:
undefined reference to `fann_train_on_file'
This fann_train_on_file is on fann_train_data.c, which is included by fixedfann.c, so why it is undefined? I don't know... :/
--update
I realized that:
$ gcc fann/fixedfann.c main.c -Ifann/include -lm
will work if I comment the headers on fixedfann.c:
//#include "config.h"
//#include "fixedfann.h"
#include "fann.c"
#include "fann_io.c"
#include "fann_train.c"
#include "fann_train_data.c"
#include "fann_error.c"
#include "fann_cascade.c"

Create a simple dynamic library

What linking step am I missing? I'm trying to make a dynamic library from file c.c:
#include "a.h"
#include "b.h"
int my_function(void)
{
return a() + EIGHT;
}
which depends on a.c:
int a(void)
{
return 1;
}
and b.h:
enum {
EIGHT = 8,
};
I run gcc -c c.c -o c.o to compile the object file. Then I run
gcc -Wall -dynamiclib -o libc.dylib c.c
and I get this error.
Undefined symbols for architecture x86_64:
"_a", referenced from:
_b in ccx5LSkL.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
How can I properly link the files? References addressing this specific problem would be awesome.
So your first line, gcc -c c.c -o c.o, compiled the object file c.o. Now you then have to use c.o for creating the final result. So your linking step should be using c.o, not c.c.
Next, the error you are getting is that the symbol "_a" was not found. This is coming from you calling the function a(), but not including it in the linking step. To do that you need to also compile a.c and include it when linking your final product.
So in total, your process should be:
1) compile:
gcc -c a.c -o a.o
gcc -c c.c -o c.o
2) link:
gcc -Wall -dynamiclib -o libc.dylib a.o c.o
Note that to compile libc.dylib, you had to include all the sources that the final result would depend on.
Finally, you don't actually need to compile all of the object files separately. You can compile and link together in one combined step by just providing the *.c files right away.
gcc -Wall -dynamiclib -o libc.dylib a.c c.c
So your problem was really just about not including both sources together. (Other than -dynamiclib, everything actually works basically just like compiling a regular executable.)

Building a shared library using gcc on Linux and MinGW on Windows

I'm having trouble with generating a build setup that allows shared libraries to be built in both Linux and Windows using gcc and MinGW, respectively. In Linux, a shared library doesn't have to resolve all dependencies at compile time; whereas, this appears to the case in Windows. Here is the problem setup:
$ cat foo.h
#ifndef FOO_H
#define FOO_H
void printme();
#endif
$ cat foo.c
#include "foo.h"
#include <stdio.h>
void printme() {
printf("Hello World!\n");
}
$ cat bar.h
#ifndef BAR_H
#define BAR_H
void printme2();
#endif
$ cat bar.c
#include "bar.h"
#include "foo.h"
void printme2() {
printme();
printme();
}
$ cat main.c
#include "bar.h"
int main(){
printme2();
}
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.so
gcc -shared bar.o -o libbar.so
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
Now, in Linux, this compiles and runs just fine:
$ make
gcc -fPIC -c foo.c
gcc -fPIC -c bar.c
gcc -fPIC -c main.c
gcc -shared foo.o -o libfoo.so
gcc -shared bar.o -o libbar.so
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ ./main
Hello World!
Hello World!
In Windows, we need to change so to dll, which is minor and fine:
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
However, when we try to build, we get the following error:
$ make
gcc -fPIC -c foo.c
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c bar.c
bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c main.c
main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o -o libbar.dll
bar.o:bar.c:(.text+0x7): undefined reference to `printme'
bar.o:bar.c:(.text+0xc): undefined reference to `printme'
collect2.exe: error: ld returned 1 exit status
make: *** [all] Error 1
Now, we can fix the error by simply including the objects from foo.o into libbar.dll:
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o foo.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ make
gcc -fPIC -c foo.c
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c bar.c
bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c main.c
main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o foo.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ ./main
Hello World!
Hello World!
However, I don't like this approach since libbar.dll now contains symbols for both foo and bar. In Linux, it only contains symbols for bar. This separation is important for situations where a library depends on some standard numerical library like BLAS. I'd like to be able to deploy the shared library and have it depend on the optimized version of the numerical library on the user's machine and not my own.
In any case, what's the proper procedure to create a shared library where not all of the symbols are present at compile time?
In case it matters, I compiled these examples with gcc 4.6.3 on Linux and mingw-get-inst-20120426.exe with gcc 4.7.2 on Windows.
On Windows, you need to create an import library for the DLL. An import library looks like a static library, in that it defines all of the needed symbols, but it doesn't have the actual function implementations, it just has stubs. The import library will resolve the "undefined reference" errors while avoiding static linking.
To create an import library with MinGW, follow the instructions here. The key is that when building the DLL, you must pass the option -Wl,--out-implib,libexample_dll.a to the linker to generate the import library libexample_dll.a.
Then, when you compile your main executable, you use the -lexample_dll option (along with -L.) to link against the import library. So with your code, I think this should work:
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll -Wl,--out-implib,libfoo.a
gcc -shared bar.o foo.o -o libbar.dll -Wl,--out-implib,libbar.a
gcc main.o -Wl,-rpath=. -L. -lbar -lfoo -o main
Also, note that on Windows, the calling convention for exported functions in DLL is almost always __stdcall, not the default __cdecl, so if you want your DLLs to be usable by other software, I'd recommend making them __cdecl. But that's not strictly requires, as long as both the code in the DLL and the header files agree on what the calling convention is.

Resources