Im creating a runtime loaded shared object in linux that impliments some JSON using jannson.h.
This is how I'm building the .so:
gcc -Wall -fPIC -c device_simulator_json.c
gcc -shared -Wl,-soname,device_simulator_json.so.1 -o device_simulator_json.so.1.0 device_simulator_json.o
When my application tries to load the .so, I get an error indication:
undefined symbol: json_object
I'm guessing that my .so has to include in it the jansson object. But I'm not sure which one or how. I can see the following jansson objects in my /usr/local/lib:
./usr/local/lib/libjansson.so.4.7.0
./usr/local/lib/libjansson.so.4
./usr/local/lib/libjansson.a
./usr/local/lib/libjansson.so
Because the .so I'm building is dynamically loaded at runtime (using dlopen), doesn't the jansson object I use also have to be built with PIC.
Thanks.
You probably should link libjansson.so inside your shared library:
gcc -L/usr/local/lib -shared -Wl,-soname,device_simulator_json.so.1 \
-o device_simulator_json.so.1.0 device_simulator_json.o -ljansson
Alternatively, you might link -ljansson into the main program (doing the dlopen). You'll better then link that program with -rdynamic
BTW, you probably should compile your shared object with all warnings and debug info:
gcc -Wall -Wextra -g -fPIC -c device_simulator_json.c
once all is debugged you might optimize with -O2
Related
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 am writing a plugin system which is separated other 3 modules:
plugin_system.c - the core of the system
list.c - contains a linked list implementation for plugins' storage
plugin_interface.h - contains the declaration needed by plugins, has no source file associated with
plugin_interface.h only contains only of types and the function:
extern int plugin_register(PluginManager *plug_manager, const char *name, Plugin *plug);
which is defined in plugin_system.c
When loading a plugin, the plugin system look for a funcion init_plugname() and call it, that function must call plugin_register to register the plugin.
The program is compiled with complex recursive Makefiles (not the best idea), but what I try to achieve is:
I compile the plugin system object in the main program folder, it is then linked with the main program. From make execution:
gcc -Wall -O2 -std=gnu99 -D DEBUG -g -fPIC -c -o /home/kowa/code/reseaux/projet/ringo/c/bin/list.o list.c
gcc -Wall -O2 -std=gnu99 -D DEBUG -g -fPIC -c -o /home/kowa/code/reseaux/projet/ringo/c/bin/plugin_system.o plugin_system.c
A plugin is compiled with gcc -fPIC -c -o plugname.o plugname.c plug_system.o followed by gcc -o plugname.so plugname.o plug_system.o -shared
I try to load the plugin in my main program and get this error:
symbol lookup error: ./plugins/zyva.so: undefined symbol: exists
exists is a function in the list module used by the plugin_system module to store plugins, the plugin_register function mentionned aboved calls it.
I've never done that kind of system before and I'm not an expert in shared library, I guess the problem is from how I compile the whole project, I may miss some linkage...
I just forgot to link the plugin with list.o which is used by the plugin_system.o...
Im wondering why Im getting no undefined references when compiling as a shared library using -shared as an option for gcc. Consider the following case:
#include <confuse.h>
int
main(int argc, char **argv)
{
cfg_opt_t opts[1];
cfg_t *cfg = cfg_init(opts, CFGF_NOCASE);
return 0;
}
libconfuse is needed here in order to run the program properly. If im compiling it as a "normal" application without specifying that libconfuse is needed (-lconfuse) im getting the following (from my perspective regular) error:
$ gcc -Wall -Wno-unused-variable test.c -o test
/tmp/ccTVz6an.o: In function `main':
test.c:(.text+0x20): undefined reference to `cfg_init'
collect2: error: ld returned 1 exit status
If im compiling the same code as a shared library im not getting any error message regarding the library:
$ gcc -Wall -Wno-unused-variable test.c -o test.so -shared
$ echo $?
0
Can someone please bring light into darkness?
You are compiling a (shared) library, not a program, and libraries are expected not to be complete, so undefined references do not prevent the shared library from building.
Yes, it may sound a bit surprising, particularly if you come from a OS (Windows?) where the shared libraries are always fully linked, but that's how ELF works.
If you want to ensure that all your references are are resolved when building a shared library you can use the linker option --no-undefined:
gcc -Wall -Wno-unused-variable test.c -o test.so -shared -Wl,--no-undefined
Note that libraries used to resolve references when linking a shared library will be added to the header of that library, as NEEDED entries, and then linked automatically when using that library. See objdump -p for details.
With shared libraries (not static ones), you could link a library libA.so into your other library libB.so.
So you could compile your shared library as:
gcc -Wall -Wno-unused-variable -fPIC test.c \
-o libmytest.so -shared -lconfuse
Later you would link that library to some main.c with
gcc -Wall main.c -lmytest -L. -o myprog
or you could load it at runtime, using dlopen(3) on ./libmytest.so (read the man page about why ./ is significant to dlopen)
Simple explanations are in the Program Library HowTo. But Drepper's paper: How to Write Shared Libraries is the best reference.
And it is permitted for a shared library (or even a static one) to have undefined references, since quite often the user of that library would explicitly link the lower level libraries needed by it.
Here is the error:
symbol lookup error: ./src/libprog3.so: undefined symbol: pow
Everything else in the library works fine, even functions that use math.h, but when I call the function that needs pow(), it crashes. It worked perfectly fine when it was a shared library. I am using gcc and a makefile to compile. The only change I made to the makefile was adding -ldl for the library. I still have -lm in it. I changed the driver program to support the change to the dll instead of the shared library, but the function causing the error hasn't changed.
Is there more to the makefile that I need to change?
Here is the makefile:
testlib: src/driver.o src/prog3.o
gcc -fPIC -Wall -c src/prog3.c -o src/prog3.o
gcc -Wall -shared -o src/libprog3.so src/prog3.o
gcc -Wall -o $# src/driver.c -ldl -lm -Lsrc -lprog3
You need to be doing:
gcc -Wall -shared -o src/libprog3.so src/prog3.o -lm
That is, shared libraries must be built with their dependencies. If you omit the -lm, you're telling the linker that unresolved symbols in libprog3.so are intended to be resolved by symbols in the main program or libraries it has already caused to be loaded. I see you did put -lm on the link command line for the main program, but my guess is that the main program did not actually use any symbols from libm.so and thus it did not get added to the DT_NEEDED table for the main program and therefore is not already loaded.
In any case, making dependencies explicit like this is almost always best.
How to create a shared object file from a static library? I am using Cygwin.
Is the following syntax correct?
gcc -shared -o libexample.so libexample.a
gcc -shared -o libexample.so -Wl,--whole-archive libexample.a
Pay attention that often you'll want the objects combined in your .so to be compiled as PIC, something you don't often want for a static library.
It might not work but you can always try:
ar -x libexample.a
gcc -shared *.o -o libexample.so
If it complains about -fPIC, then it probably won't work.