Create a simple dynamic library - c

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.)

Related

Cannot find -lCommunication collect2: error: ld returned 1 exit status

I do not know gcc and c well. In my /home/pi/Desktop/intern/adis16227_generic directory I have following 5 files.
ADIS16227.c
ADIS16227.h
Communication.c
Communication.h
main.c
main.c
#include<stdio.h>
#include "Communication.h" // Communication definitions.
int main() {
printf("hello!!\n");
unsigned char status = 0;
status = SPI_Init(0, 1000000, 1, 1);
printf("%u", status);
return 0;
}
Run command:
$ sudo gcc -L /home/pi/Desktop/intern/adis16227_generic main.c -lCommunication
Error:
/usr/bin/ld: cannot find -lCommunication
collect2: error: ld returned 1 exit status
Question:
What I am missing here?
What do I need to run the code?
-l is for libraries, and you never built a library from your Communication.c. The simplest solution is just add Communication.c to your compiler command line.
For larger projects, compile each translation unit separately with the -c switch like this:
gcc -c -Wall -Wextra -pedantic -omain.o main.c
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
and so on ... (as a suggestion, I added some common warning options here, they help you spot errors)
The resulting .o files are object code. That's already compiled machine code, but with meta-information needed for a linker to link it with other object code into a complete executable.
Then link them all with one command:
gcc -oprogram main.o Communication.o
If you actually want a library from -- say -- Communication.c and ADIS16227.c, you could compile both to object code:
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
gcc -c -Wall -Wextra -pedantic --oADIS16227.o ADIS16227.c
and then use ar to create a static library from them:
ar rcs libCommunication.a Communication.o ADIS16227.o
Then your initial compiler command would work (with the -lCommunication switch).
Final piece of advice: Never compile as root. This is completely unnecessary. So remove your sudo here.
those options:
-L /home/pi/Desktop/intern/adis16227_generic -lCommunication
suggest that the linker should find libCommunication.a (or .so) in the /home/pi/Desktop/intern/adis16227_generic directory.
But there are only sources in this directory. The linker won't build the sources of your "Communication" library for you.
So you could build the library and link with it:
gcc -c ADIS16227.c Communication.c
ar r libCommunication.a ADIS16227.o Communication.o
but maybe the fastest & quickest way to achieve a successful build would be:
sudo gcc -o main *.c
so it compiles all the files of the directory into the executable called main
Of course, it makes compilation times longer, but maybe it's not noticeable.
First move into the /home/pi/Desktop/intern/adis16227_generic directory:
cd /home/pi/Desktop/intern/adis16227_generic
Then, compile the source:
gcc ADIS16227.c Communication.c main.c -I .
You can now run your compiled program (called by default a.out):
./a.out
You have to compile separatedly files and then compile main with related obj file.
gcc -c Communication.c Communication.h
gcc main.c Communication.o -o main

Undefined reference error but symbol existing in the library

I get an undefined reference error for the example below. I have seen lots of questions that relate to this issue but believe I gave a stripped, reproducible, conceptual example as opposed specific issues in other questions,
dynlib.h:
void printMe_dyn();
dynlib.c:
#include <stdio.h>
#include "dynlib.h"
void printMe_dyn() {
printf("I am execuded from a dynamic lib");
}
myapp.c:
#include <stdio.h>
#include "dynlib.h"
int main()
{
printMe_dyn();
return 0;
}
Build steps:
gcc -Wall -fpic -c dynlib.c
gcc -shared -o libdynlib.so dynlib.o
gcc -Wall -L. -ldynlib myapp.c -o myapp
Error:
/tmp/ccwb6Fnv.o: In function `main':
myapp.c:(.text+0xa): undefined reference to `printMe_dyn'
collect2: error: ld returned 1 exit status
Proof that the symbol is in the library:
nm libdynlib.so | grep printMe_dyn
00000000000006e0 T printMe_dyn
Am I using the correct compiler flags for building the dynamic
library?
Is the proof I've presented really an unambiguous proof?
What other approach could be taken to diagnose the issue?
The order of appearance of libraries matter.
To quote the online gcc manual
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.
You should be changing your compilation statement to
gcc -o myapp -Wall -L. myapp.c -ldynlib
to tell gcc to search for the symbols used in (compiled) myapp.c to be present in dynlib.
Just as additional notice. The same behavior one may obtain when the library has been built by gcc and linked to the c++ project. Like follows:
gcc -Wall -fpic -c dynlib.c
gcc -shared -o libdynlib.so dynlib.o
g++ -o myapp -Wall -L. myapp.cpp -ldynlib
In such case the reason is name-mangling used by g++. To have it turned off one must wrap C-function prototypes by extern "C" within C-library. For example like follows:
dynlib.h:
#ifdef __cplusplus
extern "C"{
#endif
void printMe_dyn();
#ifdef __cplusplus
}
#endif
The order of libraries in linker command line matters. Fix:
gcc -o myapp -Wall -L. myapp.c -ldynlib

use a function before it's compiled

I have to compile those files in that order: a first and then b because of other requirements.
now the files are of this form:
a.h
void caller_func(void);
a.c
#include "a.h"
#include "b.h"
void caller_func(void){
called_func(void);
}
b.h
void called_func(void);
b.c
#include "b.h"
void called_func(void){
//any action
}
and on compilation i get
a.so: undefined reference to 'called_function'
is there anyway to go around this (besides changing compilation order)?
The code, as written, should not have a problem. However, you must insure that you both compile a.c into a.o and b.c into b.o and link them.
Your compile line should look something like:
gcc a.c b.c -o a.out
Or:
gcc -c a.c b.c
ld -o a.out a.o b.o
In the first example, gcc will invoke ld behind the scenes to link the executable for you. In the second example, you're explicitly carrying out the compile and link steps.
I have to compile those files in that order: a first and then b because of other requirements.
No, you don't have this requirements. Both modules have nothing todo with each other.
What you have to do is maybe linking in the correct order if one of the modules is contained in a library. But I don't think that is the problem here.
Another hint: It is not important to include the declaration before the definition here if both are identical!
What you have to do is simple: compile & link in one stage like
gcc a.c b.c -o prog
or compile in 2 steps ( order doesn't matter at all )
gcc a.c -c
gcc b.c -c
gcc a.o b.o -o prog
All this is on the assumtion you take gcc on linux. But most other compilers will behave in the same way. Feel free to ask for special compilers or environments or OSs.
"undefined reference to 'called_function'" means the linker can't find the machine code generated from compiling b.c; either you're not compiling that file, or the object code generated from compiling it isn't being included in the final link command.
Assuming gcc, you'd do something like
gcc -c a.c # compiles a.c, generates object file a.o
gcc -c b.c # compiles b.c, generates object file b.o
gcc -o prog a.o b.o # links the object files into an executable named prog
It sounds like you've written something like
gcc a.c
which compiles a.c, then attempts to link it into an executable (default name a.out or a.exe, depending on your platform).

Missing symbol compile error in C. Basic header file setup

I'm working on a C project implementing some generic containers and am having this weird issue when compiling. Here is some sample code that also replicates the error.
foo.h
void fooprint(void);
foo.c
#include "foo.h"
#include <stdio>
void fooprint(void){
printf("bar");
return;
}
main.c
#include "foo.h"
int main(void){
fooprint();
return 0;
}
I compile by typing
gcc main.c -o main
and this is what terminal outputs
Undefined symbols:
"_fooprint", referenced from:
_main in ccfMXGzj.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
I'm compiling this on an OSX system but have also tried compiling on a red hat machine with the same effect.
The solution is probably painfully obvious but I have had multiple friends I'm working with look at this and they couldnt see the problem. I've googled around a lot but most symbol error issues are usually pertaining to objective C.
You need to compile them together:
gcc -Wall -Wextra -o main main.c foo.c
Or maybe make a Makefile ?
all: main
main: main.o foo.o
main.o: main.c
foo.o: foo.c
You have to compile also foo.c into an object file and link all of them together:
gcc -o foo.o foo.c
gcc -o main.o main.c
gcc -o main main.o foo.o
Yes, this is simple, so I recommend you to read a good C book and step these easy steps.

Why am I getting a gcc "undefined reference" error trying to create shared objects?

Why am I getting an "undefined reference" error using gcc?
I am trying to create a shared object (.so) that exports one function, "external()". I then try to link against the .so but get "undefined reference 'external'". What am I doing wrong here?
File: external.c
int external() {
return 5;
}
File: program.c
int external();
int main(char** argv, int* argc) {
return external();
}
Commands:
$ gcc -fPIC -c external.c
$ gcc -shared -o libexternal.so external.o
$ gcc -L. -lexternal -o program program.c
/tmp/cc3MmhAE.o: In function `main':
program.c:(.text+0x7): undefined reference to `external'
collect2: ld returned 1 exit status
I can even run nm and see that the .so is defining 'external':
Command:
$ nm libexternal.so | grep external
0000040c T external
What am I missing here?
Recent versions of gcc/ld default to linking with --as-needed.
This means if you write -lexternal before the C file the library will automatically get excluded (the order matters when testing if things are "needed" like this)
You can fix this with either of:
gcc -L. -o program program.c -lexternal
gcc -L. -Wl,--no-as-needed -lexternal -o program program.c
The latter of which passes --no-as-needed to the linker, which would cause the library to still be linked, even if you didn't call external() from it.
Note: -Wl,--no-as-needed isn't applied globally to everything that's linked, it's only applied to things that follow it in the command line order. So -lexternal -Wl,--no-as-needed also wouldn't work. This does mean that you can mix and match behaviours though, for example gcc -L. -Wl,--no-as-needed -lexternal -Wl,--as-needed -o program program.c -lmightneed would always link against external, but only link against mightneed if one or both of program.c/libexternal.so caused it to be needed.

Resources