I want to create a shared library from several static libs using GCC under OS X.
In some static libs, there's no code in shared library call it, I just want to export the symbols in these static libs. This works under debug mode, but doesn't under release mode (especially when I enable the dead code striping). I can understand the reason, gcc think these functions on static libs are never used. but how can I force gcc to include these symbols?
I already tried adding -u option for loader, but it only generates a 'local' symbol. how to make linker generate an export symbol?
Also, I'm wondering if there's a way to add the linker directives in source code, just like the MSVC #pragrma comment(linker, "/INCLUDE:xxxx")
the function I defined in static lib is like:
extern "C"
void test() {}
Thanks in advance!
-Jonny
Have you tried --whole-archive?
Use ar to disassemble the static libraries into their constituent object files. Then link those objects together to make the shared library.
ar -x libstatic.a
(produces a bunch of *.o files)
gcc -shared -olibshared.so *.o # Linux
ld -dylib -olibshared.dylib *.o # Mac OSX
Related
I've made program, which formats storage devices. However, when I've created library (for python GUI) based on this program it starts to show the error:
/usr/bin/ld: fdisk/libfdisk.a(la-label.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
libfdisk.a, which I use, has been built from source util-linux-2.35.
And when -lfdisk is used instead of libfdisk.a, it compiles with no errors.
Compiles with errors:
g++ file1.cpp file2.cpp ... -o package.name ... libfdisk.a
Compiles correctly:
g++ file1.cpp file2.cpp ... -o package.name ... -lfdisk
What the difference between these 2 ways?
But there is another, optional, question about fdisk. When I compile my program (not library) with -lfdisk, program can not create 2 partitions due to error 28 (returns from fdisk_add_partition(...)).
I'll share the code if it needs.
With -lfdisk the linker is asked to figure out which library file exactly to use.
The usual linkers on Linux will prefix lib and then search for files with .so or .a ending in the library path, which because you didn't specify any, will be the system library path (probably /usr/lib/ or similar). If a .so is found, it will be preferred for linking if a static link wasn't requested.
Your other method will explicitly add in the file named libfdisk.a in the current directory. That is a static library, not a shared one, and if you try to build a shared library from it, then you need to have compiled libfdisk.a with -fPIC or if you try to build a PIE executable at least with -fPIE. If you are trying to build a non-PIE executable, then neither flag is required. GCC may be configured to build PIE by default (as a hardening measure).
So you are probably linking two completely different files.
I have a rather complex build I'm trying to do, but I'll simplify it a little bit for this question. I have three c++ files (main.cpp file2.cpp and file3.cpp) that I am trying to compile and link against 3 static libs (libx.a liby.z libz.a) to produce an executable.
There are many dependencies involved.
All three c files are dependent on all 3 libs. libx is dependent on liby and libz. And finally, libx is also dependent on several callback functions contained in file2.cpp.
What command line would build this correctly? I have tried dozens of variations and nothing has satisfied the linker yet.
If it matters, the libs are pure c code compiled with gcc. Sources are c++ and I'm compiling/linking with g++. I have this working correctly as a visual studio project, and am trying to port to linux.
From your post:
g++ main.cpp file2.cpp file3.cpp -lx -ly -lz
However, if static linking is causing you problems, or you need to distribute any of the libs, then you may consider making them shared objects (.so files, commonly called DSOs). In that case, when you build libx.a, for example, compile all the sources to object files, and then combine them with
g++ -shared *.o -o libx.so -ly -lz
(this version assumes that liby.a and libz.a are stills static, and will be combined into libx.so
You may need to use extern "C" { } in your .cpp files to include the header for the C libs.
See Including C Headers in C++ in How To Mix C and C++.
I use log4cxx logging library. I need to link with its static version to avoid additional binary dependencies. I use it in my dynamic library. Default build of log4cxx produces static library but I cannot link with it because it was compiled w/o -fPIC flag. So I changed log4cxx bulding as:
CPPFLAGS="-fPIC -static" ./configure
make
As a result I received a liblog4cxx.a that I can link with my .so library. Linking was done by Cmake, something like:
target_link_libraries(my_dynamic_lib log4cxx)
link_directories(relative_path_to_dir_where_liblog4cxx.a_lives)
Everything looked fine until runtime. I cannot load my_dynamic_lib.so because of undefined symbol "logger"
Please explain me what's wrong and how to resolve this problem.
thanks
You can verify whether the shared library contains the symbol by using
nm -g my_dynamic_lib.so | grep logger
If it is shown with symbol type U it means it's undefined.
Normally a shared library will not resolve all the symbols it needs until run-time, so it is possible (and perfectly normal) to link a shared library with missing symbols.
If you put -llog4cxx at the start of the linker command line for my_dynamic_lib.so then it won't link to any of the code in there, and will leave the logger symbol unresolved until run-time. To force it to use the symbols in the static library make sure you list the static library after the objects that need it:
g++ -fPIC -shared -o my_dynamic_lib.so obj1.o obj2.o -llog4cxx ...
I don't know how to do that with cmake, but it looks as though your CMakefile only links to log4cxx when linking the main executable, not the dynamic library.
Usually you would link liblog4cxx.a with your executable and not with your my_dynamic_lib.so. I don't think you can link like in your example unless you can provide documentation that says otherwise.
I am trying to use --whole-archive option, but it seems to not work with -Xlinker. How can I add this option by using -Xlinker ?
Here is the whole story:
I write a main program A, and several shared libraries B1,B2,etc. main program will use dlopen to load these shared libraries at runtime. I compile main program A linking with ALL the possible static libraries used by main program (S1,S2...etc) or shared libraries (S3,S4...etc). then I compile shared library without static library.
When calling dlopen, the program fail because of undefined symbol in shared library. this symbol does exist in static library S3, but I can not find it in symbol table of main program.
So I add --whole-archive option when compiling main program, but the symbol still not exists in final binary. how can I add this symbol to main program while it is not direct used in main program.
So I add --whole-archive option when compiling main program
You still have not answered the question: what command line you used. Adding linker options when compiling in generally pointless: they only matter when linking.
The correct link line for the situation you described is (assuming you are using GCC on a UNIX/ELF system):
gcc -rdynamic -o exename main.c \
-Wl,--whole-archive -lS1 -lS2 -Wl,--no-whole-archive
Explanation of important points:
The -rdynamic is needed so that symbols defined in the main
executable are visible to dlopened shared libraries.
Libraries should follow sources on the link line (order of libraries and sources matters).
Libraries which you want to link in entirely should be surrounded by --whole-archive and --no-whole-archive options.
EDIT: I suppose I should clarify, in case it matters. I am on a AIX Unix box, so I am using VAC compilers - no gnu compilers.
End edit
I am pretty rusty in C/C++, so forgive me if this is a simple question.
I would like to take common functions out of a few of my C programs and put them in shared libraries or shared objects. If I was doing this in perl I would put my subs in a perl module and use that module when needed.
For the sake of an example, let's say I have this function:
int giveInteger()
{
return 1034;
}
Obviously this is not a real world example, but if I wanted to share that function, how would I proceed?
I'm pretty sure I have 2 options:
Put my shared function in a file, and have it compile with my main program at compile time. If I ever make changes to my shared function, I would have to recompile my main program.
Put my shared function in a file, and compile it as a shared library (if I have my terms correct), and have my main program link to that shared library. Any changes I make to my shared library (after compiling it) would be integrated into my main program at runtime without re-compiling my main program.
Am I correct on that thinking?
If so, how can I complish either/both of those methods? I've searched a lot and I seem to find information how how I could have my own program link to someone else's shared library, but not how to create my own shared functions and compile them in a way I can use them in my own program.
Thanks so much!
Brian
EDIT: Conclusion
Thanks everyone for your help! I thought I would add to this post what is working for me (for dynamic shared libraries on AIX) so that others can benefit:
I compile my shared functions:
xlc -c sharedFunctions.c -o sharedFunctions.o
Then make it a shared object:
xlc -qmkshrobj -qexpfile=exportlist sharedFunctions.o
xlc -G -o libsharedFunctions.so sharedFunctions.o -bE:exportlist
Then link it another program:
xlc -brtl -o mainProgram mainProgram.c -L. -lsharedFunctions
And another comment helped me find this link, which also helped:
http://publib.boulder.ibm.com/infocenter/comphelp/v7v91/topic/com.ibm.vacpp7a.doc/proguide/ref/compile_library.htm
Thanks again to all who helped me out!
Yeah you are correct. The first is called a static library, while the second is called a shared library, because the code is not bound to the executable at compile time, but everytime again when your program is loaded.
Static library
Compile your library's code as follows:
gcc -c *.c
The -c tells the program not to link the object file, but just leaves you with object files for each .c file that was compiled. Now, archive them into one static library:
ar rcs libmystuff.a *.o
man ar will tell you what the rcs options mean. Now, libmystuff.a is a archive file (you can open it with some zip-file viewers) which contain those object files, together with an index of symbols for each object file. You can link it to your program:
gcc *.c libmystuff.a -o myprogram
Now, your program is ready. Note that the order of where the static libraries appear in the command matter. See my Link order answer.
Shared library
For a shared library, you will create your library with
gcc -shared -o libmystuff.so *.c
That's all it takes, libmystuff.so is now a shared object file. If you want to link a program to it, you have to put it into a directory that is listed in the /etc/ld.so.conf file, or that is given by the -L switch to GCC, or listed in the LD_LIBRARY_PATH variable. When linking, you cut the lib prefix and .so suffix from the library name you tell gcc.
gcc -L. -lmystuff *.c -o myprogram
Internally, gcc will just pass your arguments to the GNU linker. You can see what arguments it pass using the -### option: Gcc will print the exact arguments given to each sub process.
For details about the linking process (how some stuff is done internally), view my Linux GCC linker answer.
You've got a third option. In general, your C++ compiler should be able to link C routines. The necessary options may vary from compiler to compiler, so R your fine M, but basically, you should be able to compile with g++ as here:
$ g++ -o myapp myapp.cpp myfunc.c giveint.c
... or compile separately
$ gcc -c myfunc.c
$ gcc -c giveint.c
$ g++ -c myapp.cpp
$ g++ -o myapp myapp.o myfunc.o
You also need to include your declaration of the functions; you do that in C++ as
extern "C" {
int myfunc(int,int);
int giveInterger(void);
}
You need to distinguish between recompiling and relinking.
If you put giveInteger() into a separate (archive) library, and then modify it later, you'll (obviously) need to recompile the source file in which it is defined, and relink all programs that use it; but you will not need to recompile such programs [1].
For a shared library, you'll need to recompile and relink the library; but you will not have to relink or recompile any of the programs which use it.
Building C++ shared libraries on AIX used to be complicated; you needed to use makeC++SharedLib shell script. But with VAC 5.0 and 6.0 it became quite easy. I believe all you need to do is [2]:
xlC -G -o shr.o giveInteger.cc
xlC -o myapp main.cc shr.o
[1] If you write correct Makefile (which is recommended practice), all of this will happen automatically when you type make.
[2] There is a certain feature of AIX which may complicate matters: by default shared libraries are loaded into memory, and "stick" there until subsequent reboot. So you may rebuild the shr.o, rerun the program, and observe "old" version of the library being executed. To prevent this, a common practice is to make shr.o world-unreadable:
chmod 0750 shr.o