Problems when linking shared library - c

Below are the steps of how I generate the executable file using shared library.
I have three files:
File libhello.c
/* hello.c - demonstrate library use. */
#include <stdio.h>
void hello(void)
{
printf("Hello, library world./n");
}
File libhello.h
/* hello.h - demonstrate library use. */
void hello(void);
File main.c
/* main.c -- demonstrate direct use of the "hello" routine */
#include "hello.h"
int main(void)
{
hello();
return 0;
}
I use the commands below to generate the shared library.
gcc -g -Wall -fPIC -c hello.c -o hello.o
gcc -shared -W,soname,-libhello.so.0 -o libhello.so.0.0.0 hello.o
Finally, I add the library path to the LD_LIBRARY_PATH variable and try to create the executable file using the shared library.
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
ln -s libhello.so.0.0.0 libhello.so.0
gcc -g -Wall -c main.c -o main.o -I.
gcc -o main main.o -lhello -L.
However, at the last step, there is one error: can't find -lhello. So, where am I wrong?
Thanks.

gcc looks for libhello.so when linking a new program. libhello.so.0 is used when the dynamic dependencies of an already linked program are searched.
In other terms: gcc -o main main.o -lhello -L. looks for libhello.so, and ./main looks for libhello.so.0. This allows to have multiple versions of a library available for legacy programs while precisely identifying the library that matches the installed headers.
A symlink libhello.so -> libhello.so.0.0.0 should do the trick.

Related

How do you link two files in make, that both include a different library?

I want to test my code in test.c which includes main.h with all the function declarations from main.c. I want to compile my test.c file with criterion, which on its own works fine like this: cc -c test.c -o testing -I include -L lib -l criterion.3.1.0 and I compile my main.c in the same way and it works fine: cc main.c -o output -I include -L lib -l SDL2-2.0.0. But when I want to include a function from main.c in test.c it gives me a linking error.
The project architecture is like this:
main.c
#include "main.h"
int function1(){
[...]
}
test.c
#include "main.h"
#include <criterion/criterion.h>
Test(sample,test_function1){
cr_assert(function1() == 1);
}
main.h
#include <SDL2/SDL.h>
extern int function1();
How do I have to compile/link these files in order to have my test-file use get access to the functions from main.c?
What you are currently doing is compiling and linking the binary in a single command for each source file in your project. The linker, with how you are doing this, is not aware of your other sources. Instead, you should first build the object files for each source file, and then you can link those together to form your binary.
Building object files:
cc -c main.c -I include -o main.o
cc -c test.c -I include -o test.o
Linking:
cc -o testing main.o test.o -Llib -lcriterion.3.1.0 -lSDL2-2.0.0

Where to change LD_LIBRARY_PATH

I want to compile these files into executable.
//main.c
#include <stdio.h>
#include <mylib.h>
int main(void){
call_hello_world();
return 0;
}
//mylib.h
void call_hello_world(void);
//mylib.c
#include <mylib.h>
#include <stdio.h>
void call_hello_world( void ) {
printf( ”Hello world!” );
}
I tried
gcc -c -I. -fPIC -o mylib.o mylib.c
gcc -shared -o libmylib.so mylib.o
gcc -c -o main.o main.c
gcc -o hello main.o -L. -lmylib
but at the third step, I got stucked because it couldn't find my 'mylib.h'. My professor said I needed to change 'LD_LIBRARY_PATH' so I tried to add this export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/dev/shm my .zshrc but it still didn't work for me. Any suggestions what I should do?
There are several issues with your approach.
First, there is a difference between including a header file like this #include <mylib.h> and including it like that #include "mylib.h".
The first option is usually used to include standard library header files, that should be located in the standard set of directories according to the FHS on Linux.
The latter is the option you might want to use as it is usually used to include user-defined headers and tells the preprocessor to search in the directory of the file containing the directive. (See #quest49 answer's https://stackoverflow.com/a/21594/3852949)
The LD_LIBRARY_PATH environment variable is used to indicate where libraries should be searched for first before looking into the standard set of directories.
So what you would want to do to make your main.c file compile, and after changing #include <mylib.h> directive to #include "mylib.h", is to either :
Add the include file into the directory where your main.c file is located
Indicate where the include file path is with -I option to gcc
These are the commands needed :
gcc -c -I. -fPIC -o mylib.o mylib.c
gcc -shared -o libmylib.so mylib.o
gcc -c -I. -o main.o main.c
gcc -o hello main.o libmylib.so
Then in your shell:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/full/path/of/directory/containing/libmylib-so

Unable to identify issue GNU archiver. Compiling with *.o works but libname.a dosen't

I'm trying to make a static library (.a) but facing issues that I'm unable to understand. So in brief compiling with *.o succeeds but archiving them using ar and then using the .a file to compile gives me an undefined reference to 'symbol' error.
So here is a simple code.
test.c
#include <stdio.h>
#include <string.h>
int main()
{
hello_world();
return 0;
}
hello_world.c
#include<stdio.h>
void hello_world (void) {
printf("Hello World\n");
}
Compile.
gcc -c -o hello_world.o hello_world.c
ar crs libhello.a hello_world.o
gcc libhello.a -o test test.c
gives me the error
/tmp/ccsO7AJl.o: In function `main':
test.c:(.text+0xa): undefined reference to `hello_world'
Instead doing this works(Compiles and runs fine)
gcc -c -o hello_world.o hello_world.c
gcc hello_world.o -o test test.c
I have no idea what I have done wrong so any help is appreciated.
This is an almost duplicate of Why does the order of '-l' option in gcc matter? - but the behaviour can be replicated without the -l switch by specifying the archive name on command line.
The GNU linker as executed by GCC will, by default, link from left to right, and only use those .o files from the library archive that are needed to satisfy undefined references so far. Since your library precedes the main translation unit on the command line, hello_world is not required at the time the linker is processing it.
The solution is to mention the library after the translation units/object files that depend on it:
gcc -o test test.c libhello.a

C - programming a makefile and how they work

So given three files:
main.h
#include <stdio.h>
void printFunc(*char);
main.c
#include "main.h"
int main(){
printFunc("Hello World\n");
return 0;
}
printFunc.c
#include "main.h"
void printFunc(char *string){
printf("%s", string);
return;
}
You can compile using gcc on a linux machine as follows:
gcc -g -Wall -c file1.c //compile but do not link file
gcc -g -Wall -c file2.c //same
gcc file1.o file2.o -o main //executable "main"
or
gcc -g -Wall file1.c file2.c -o main
But I am concerned with how the header file gets included. I came across this when I was working on creating a "makefile" when I noticed that some tutorials will do something like this:
main : main.o printFunc.o
gcc -o main main.o printFunc.o
main.o : main.c
gcc -g -Wall -c -o main.o main.c
printFunc.o : printFunc.c
gcc -g -Wall -c -o printFunc.o printFunc.c
and others will include the header file as a dependent with:
main : main.o printFunc.o //main.h EDIT
//commands
main.o : printFunc.o main.h
//commands
Finally:
So, is it necessary to include the header file as a dependent to the executable? When does the include file get placed within the sources?
And also one could use this command:
executableName : dependencies.o //and a header file?
gcc -g -Wall -o executableSource.c
Which could be done with the line:
gcc -g -Wall -o executableName executableSource.c
Will the second command be run but the first is shorthand notation?
And finally, I thought the "-o" command was "send output to", if you will. If that way, it seems intuitive to run the command like:
gcc compileThisFile andSendOutputTo thisExecutableFile
gcc someSource.c -o executableFile
But with the notation listed above its more like:
gcc sendOutputTo thisExecutableFile fromThisSource
Is that correct?
main : main.o printFun.o main.h is definitely wrong. That's saying that the header is a prerequisite for linking. A header is a prerequisite for compilation.
Assuming what you really meant was to specify the header as a compilation dependency (e.g. printFunc.o : printFunc.c printFunc.h), this means that if the header changes, the object file will be automatically regenerated. If you don't, then it won't.
A dependency in Makefile is saying that whenever any of the listed files change, run the command again. It does not mean that the listed file will be included into the compilation or linking. You still need the regular #include "main.h" in your sources.
Thus, this works too:
printFunc.o : printFunc.c someReadmeFile.txt
gcc -g -Wall -c -o printFunc.o printFunc.c
Whenever printFunc.c or someReadmeFile.txt is updated, gcc -g -Wall .... will be executed again.
I hope it's clearer now.

Build .so file from .c file using gcc command line

I'm trying to create a hello world project for Linux dynamic libraries (.so files). So I have a file hello.c:
#include <stdio.h>
void hello()
{
printf("Hello world!\n");
}
How do I create a .so file that exports hello(), using gcc from the command line?
To generate a shared library you need first to compile your C code with the -fPIC (position independent code) flag.
gcc -c -fPIC hello.c -o hello.o
This will generate an object file (.o), now you take it and create the .so file:
gcc hello.o -shared -o libhello.so
EDIT: Suggestions from the comments:
You can use
gcc -shared -o libhello.so -fPIC hello.c
to do it in one step. – Jonathan Leffler
I also suggest to add -Wall to get all warnings, and -g to get debugging information, to your gcc commands. – Basile Starynkevitch

Resources