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
Related
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
I am using GNU g++ 4.9.2 compiler both on Solaris and Linux.
On Solaris platform, to create a shared library from a source file (a.c), I use the following command:
g++ -G a.c -o a
a becomes a shared library
a.c contains the following code:
void libfn1()
{
}
If I try not to use -G option i.e. compile as:
g++ a.c -o a
It gets a linker error: Undefined Symbol main
But, on Linux, if I do the same thing: it says:
g++: error: unrecognized command line option -G
How to create a shared library on Linux? What is the g++ option for that?
The g++ documentation says this:
These additional options are available on System V Release 4 for
compatibility with other compilers on those systems:
-G Create a shared object. It is recommended that -symbolic or -shared be
used instead.
Normally you want to generate position independent code too, for a shared library, with the -fPIC flag.
So you'd want to run:
g++ -fPIC -shared a.c -o liba.so
The process to create a shared library on a Linux system is a bit different.
Shared libraries on Linux are .so (for "shared object") files, not .g.
You do it like this:
First, you need to generate position-independent code from your C++ source. That is so your library works from wherever it is called. To do that, you should use g++'s -fPIC flag.
So, for each source file you want to be included in your library, you should only compile it to position-independent code. We'll handle linking later.
For each source file:
g++ -c -fPIC file.cpp
(The -c flag tells g++ "compile, don't link").
for each file.cpp, g++ will generate file.o, an object file containing position-independent code.
To then build the object files into a shared library, you should use
g++ -o -shared myLibrary.so {all_object_files}
So if you have file1.o, file2.o and file3.o, the command would be:
g++ -shared -o myLibrary.so file1.o file2.o file3.o
Of course, if you have a lot of files this can get pretty tedious, so you should write a Makefile to automate this process for you! Here's an example:
myLibrary.so: file1.o file2.o file3.o
$(CXX) -shared $^ -o $#
file1.o file2.o file3.o : CXXFLAGS+=-fPIC
I wrote a C programm and saved it with a .c extension.
Then I compiled with the gcc but after that I only see my .c file and an .exe file. The program runs perfectly. But where is the .o file that I learned in theory? Has it been overwritten to .exe and all done by the gcc in on step? (Preprocessing, compiling, assembling and linking)
I'm on a VM running Debian.
By default, gcc compiles and links in one step. To get a .o file, you need to compile without linking. That's done with the -c option.
Suppose you want to compile two files separately, then link them. You would do the following:
gcc -c file1.c # creates file1.o
gcc -c file2.c # creates file2.o
gcc -o myexe file1.o file2.o
If you want just the output of the preprocessor, use the -E option along with the -o to specify the output file:
gcc -E file1.c -o file1-pp.c # creates file1-pp.c
Compile and link in two steps:
gcc -Wall -c tst.c
gcc tst.c -o tst
After first command you'll get a .o file.
if you did something like gcc test.c then it produces only the executable file (in order to compile only, see the -c option)
here is steps on compiling with gcc to create a .o file from your C file:
http://www.gnu.org/software/libtool/manual/html_node/Creating-object-files.html
I have Ubuntu 64 bit installed, and when I compile C files using the flags:
gcc -g -m32 -ansi -Wall -c -o *.o *.c
it compiles the files, but when I try to run them in the terminal, nothing happens.
So I decided to try to compile and run just one simple file without a makefile, with the following code:
#include <stdio.h>
int main()
{
printf("Hello World");
return 0;
}
The compilation succeeds but when I try to run the file I get nothing...
Note: I already tried to install lib32gcc1, libc6-i386, and g++-multilib.
How can I fix this problem?
Replace -o *.o by -o programname. The -o parameter receives the executable name of the program you're generating. And here is gcc manual:
http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Overall-Options.html#Overall-Options
For a simple test, leave every option out:
> cat test.c
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
> gcc test.c
> ./a.out
Hello World
and see if that works.
Let us assume you (already) have two object files a.o and b.o, their corresponding source file a.c and b.c and some common header ch.h; then your (incorrect) command line
gcc -g -m32 -ansi -Wall -c -o *.o *
might be expanded as:
gcc -g -m32 -ansi -Wall -c -o a.o b.o a.c b.c ch.h a.o b.o
(actually, that would be even worse, e.g. if you have some Makefile or some backup files from your editors like a.c~, as remarked by William Pursell)
which would compile but not link, the files b.o a.c b.c ch.h a.o b.o which does not means much.
You should understand that the shell is expanding first the arguments before executing any gcc program (in a new process). To understand what is expanded, consider replacing gcc by echo (or by gcc -v which would show what is really happening)
Then, you should read the GCC documentation about invoking GCC
Actually, you need to spend several hours in reading, e.g. Advanced Bash Scripting Guide (which does have some mistakes perhaps) and Advanced Linux Programming. Several wikipedia pages could also be useful to read.
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.