Here is a C++ project, and its lib dependency is
Hello.exe
-> A.so
-> B.a
B.a
-> A.so
Hello.exe depends on B.a and A.so, and B.a depends on A.so.
GCC compiler will link Hello.exe successful?
And if there is a b.cc file in B.a which includes a header file a.h of A.so, and also uses some interfaces of A.so, then with right "include" path setting, compiling b.cc to b.o should be successful.
But if without A.so as input, the link of B.a would be failed, right?
gcc -c b.cc -I../A/include ;; successful
gcc -a B.a b.o ;; fail
Where I can find detail library link documents about these complex reference relationship ...
Thanks.
A static library is just a collection of object files created from compiled .c/.cpp files.
It cannot have link relationships.
You will need to specify link dependencies to both A.so and B.a when you compile Hello.exe
off the top of my head it would be something like
gcc -o Hello.exe B.a A.so
As a side note you should rename A.so to libA.so and instead do
gcc -o Hello.exe -lA B.a
Linking to A.so directly like example 1 will require that A.so is always in the same directory as Hello.exe
If you use example 2, you can put libA.so anywhere and use LD_LIBRARY_PATH to point to the right directory.
Related
Say I have a.so and b.so.
Can I produce c.so as a single shared library with all the functions exported by a and b, of course resolving all intra-dependencies (i.e. all functions of b.so called by a.so and the other way around)?
I tried
gcc -shared -Wl,soname,c.so -o c.so a.so b.so
but it doesn't work.
Same goes if I archive a.o and b.o in a.a and b.a (which shouldn't modify a.o and b.o), and do
gcc -shared -Wl,soname,c.so -o c.so a.a b.a
Thanks
Merging multiple shared libraries into one is indeed practically impossible on all UNIXen, except AIX: the linker considers the .so a "final" product.
But merging archives into .so should not be a problem:
gcc -shared -o c.so -Wl,--whole-archive a.a b.a -Wl,--no-whole-archive
In practice it is not possible.
From linker point of view, a SO library is a final product that does not contain relocation information required for linking.
If you have access to either source or object files for both libraries, it is straightforward to compile/link a combined SO from them.
Using the example from this great answer about the link order in gcc, I tried the following:
echo 'extern int b; int a = b;' > b.cpp
g++ -c b.cpp -o b.o
ar cr libb.a b.o
echo 'int b;' > d.cpp
g++ -c d.cpp -o d.o
ar cr libd.a d.o
echo 'extern int a; int main() { return a; }' > a.cpp
g++ a.cpp -o a1 d.o b.o # Works
g++ a.cpp -o a2 libd.a libb.a # Fails
If the .a file is simply an archive file containing one or several .o files, how come linking with the lib*.a files (in the wrong order, as stated in the original answer) fails, but using the .o files directly (in the same order) works?
As far as the linker is concerned, the difference between a static library and an object file
in the linkage sequence is:-
An object file is to be linked, just because it is an object file, whether or not it provides
definitions of any symbols that the executable needs. If you don't want an object
file to be linked, don't mention it to the linker.
A static library is an archive of object files that are to be extracted from the
library and linked if required, where an object file in a library is required
if and only if it provides a definition of at least one hitherto undefined
symbol that the linker has observed in an object file or library appearing earlier in
the linkage sequence.
For background, I'm creating some C++ software that uses dynamically loaded shared library plugins for hardware output (the specifics of it aren't relevant here).
I'm building the executable by compiling everything into object files and then linking the ones needed, which is simple using an exclusion list. I can then build the shared library by specifying its primary object file (the one that's dynamically loaded and accessed at runtime) along with every other object file referenced by the primary one.
My question is this: Is there a way to provide the linker with the primary object file, and create a shared library containing only the objects it depends upon? All of the object files are in the same directory, I'm not using a Makefile (yet; if one could solve the problem, it's a valid answer), and compilation speed isn't an issue.
I've looked into the linker options --as-needed, --gc-sections, and --no-undefined, but I haven't been able to piece together a working build process.
Example: For source files main.cpp, a.cpp, b.cpp, a.h, and b.h, where main.cpp and a.cpp both include b.h:
gcc -fPIC -c *.cpp -I. builds object files main.o, a.o, and b.o.
gcc -o main.out *.o builds the final executable main.out from the object files... including a.o, which is unused. (--gc-sections should fix this.)
gcc -fPIC -shared -o a.so a.o -Wl,--as-needed !(a).o builds the final shared library a.so from all of the object files... including main.o, which is unused. How do I prevent main.o from being included in a.so?
Is there a way to provide the linker with the primary object file, and create a shared library containing only the objects it depends upon?
Yes: package all objects into an archive library liball.a, then link like this:
gcc -shared -o a.so a.o liball.a
The linker will then pull out from liball.a all objects that a.o depends on, and only these objects, as explained here.
Note: liball.a may contain a.o, there is no harm (as above link explains).
Update:
Is there a way to do it without needing to create an archive first?
I don't know of any portable way to do that. The Gold linker has --start-lib and --end-lib command line flags that achieve exactly that.
I am attempting to build an executable from three static libraries using scons. However, even though the source files have the .cc suffix, gcc is selected to link the final executable instead of g++. The following SConstruct demonstrates this issue.
lib_a = Library('a.cc')
lib_b = Library('b.cc')
lib_c = Library('c.cc')
Program('prog',[lib_a,lib_b,lib_c])
This then output the following commands to be run.
g++ -o a.o -c a.cc
g++ -o b.o -c b.cc
g++ -o c.o -c c.cc
ar rc liba.a a.o
ranlib liba.a
ar rc libb.a b.o
ranlib libb.a
ar rc libc.a c.o
ranlib libc.a
gcc -o prog liba.a libb.a libc.a
As far as I understand, the Program builder cannot determine from suffix alone whether these libraries came from C or C++ source files, and then chooses C. I know that I could work around this by specifying that C code should be linked using g++ instead of gcc, but that feels dirty. Is there some way to tell scons that it should link this program as C++ code instead of C?
SCons tries to pick a linker, based on the suffixes of the given source files. Since you're sticking the libraries right into the Program Builder, SCons is not able to see that they stem from C++ files (they have the "*.a" extension now). That's why the "smartlink" functionality of SCons switches to its default, which is "$CC" = "gcc" in your case above.
Against this, you could restructure your build a little, and make it look more like this:
lib_a = Library('a.cc')
Program('prog', 'main.cc', LIBS=['a'], LIBPATH=['.'])
Now, SCons is able to derive the linker from the file type of "main.cc"...and correctly calls the "g++" executable (if it can be found in the current path).
I'm not advocating this (the above method should be preferred), but another option would be to simply overwrite the linker that gets used with:
Program('prog', ..., LINK='g++')
Following up on #dirkbaechle's answer, realize that main.cc doesn't have to have any content. You can leave all of your code (including main() in your libraries and just provide a blank main.cc.
One convenient way to supply a blank main.cc is Textfile():
env = Environment(tools=['default', 'textfile'])
lib_a = env.Library('a.cc')
lib_b = env.Library('b.cc')
lib_c = env.Library('c.cc')
main_cc = env.Textfile('main.cc', [])
env.Program('prog',[main_cc, lib_a,lib_b,lib_c])
This way, you don't have to add any files to your source code, since main.cc will be created when it is needed.
What is the difference between these two file types. I see that my C++ app links against both types during the construction of the executable.
How to build .a files? links, references, and especially examples, are highly appreciated.
.o files are objects. They are the output of the compiler and input to the linker/librarian.
.a files are archives. They are groups of objects or static libraries and are also input into the linker.
Additional Content
I didn't notice the "examples" part of your question. Generally you will be using a makefile to generate static libraries.
AR = ar
CC = gcc
objects := hello.o world.o
libby.a: $(objects)
$(AR) rcu $# $(objects)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
This will compile hello.c and world.c into objects and then archive them into library. Depending on the platform, you may also need to run a utility called ranlib to generate the table of contents on the archive.
An interesting side note: .a files are technically archive files and not libraries. They are analogous to zip files without compression though they use a much older file format. The table of contents generated by utilities like ranlib is what makes an archive a library. Java archive files (.jar) are similar in that they are zip files that have some special directory structures created by the Java archiver.
A .o file is the result of compiling a single compilation unit (essentially a source-code file, with associated header files) while a .a file is one or more .o files packaged up as a library.
D Shawley's answer is good, I just wanted to add a couple of points because other answers reflect an incomplete understanding of what's going on.
Keep in mind that archive files (.a) are not restricted to containing object files (.o). They may contain arbitrary files. Not often useful, but see dynamic linker dependenciy info embedded in an archive for a stupid linker trick.
Also notice that object files (.o) are not necessarily the result of a single compilation unit. It is possible to partially link several smaller object files into a single larger file.
http://www.mihaiu.name/2002/library_development_linux/ -- search in this page for "partial"
There is one more aspect of linking against .a vs .o files: when linking, all .os passed as arguments are included in the final executable, whereas entries from any .a arguments are only included in the linker output if they resolve a symbol dependency in the program.
More specifically, each .a file is an archive comprising multiple .o files. You can think of each .o being an atomic unit of code. If the linker needs a symbol from one of these units, the whole unit gets sucked into the final binary; but none of the others are unless they too are needed.
In contrast, when you pass a .o on the command line, the linker sucks it in because you requested it.
To illustrate this, consider the following example, where we have a static library comprising two objects a.o and b.o. Our program will only reference symbols from a.o. We will compare how the linker treats passing a.o and b.o together, vs. the static library which comprises the same two objects.
// header.hh
#pragma once
void say_hello_a();
void say_hello_b();
// a.cc
#include "header.hh"
#include <iostream>
char hello_a[] = "hello from a";
void say_hello_a()
{
std::cout << hello_a << '\n';
}
// b.cc
#include "header.hh"
#include <iostream>
char hello_b[] = "hello from b";
void say_hello_b()
{
std::cout << hello_b << '\n';
}
// main.cc
#include "header.hh"
int main()
{
say_hello_a();
}
We can compile the code using this Makefile:
.PHONY = compile archive link all clean
all: link
compile:
#echo ">>> Compiling..."
g++ -c a.cc b.cc main.cc
archive: compile
#echo ">>> Archiving..."
ar crs lib.a a.o b.o
link: archive
#echo ">>> Linking..."
g++ -o main_o main.o a.o b.o
g++ -o main_a main.o lib.a
clean:
rm *.o *.a main_a main_o
and obtain two executables main_o and main_a that differ in that the contents of a.cc and b.cc where provided through two .os in the first case and through a .a in the second.
Lastly we examine the symbols of the final executables using the nm tool:
$ nm --demangle main_o | grep hello
00000000000011e9 t _GLOBAL__sub_I_hello_a
000000000000126e t _GLOBAL__sub_I_hello_b
0000000000004048 D hello_a
0000000000004058 D hello_b
0000000000001179 T say_hello_a()
00000000000011fe T say_hello_b()
$ nm --demangle main_a | grep hello
00000000000011e9 t _GLOBAL__sub_I_hello_a
0000000000004048 D hello_a
0000000000001179 T say_hello_a()
and observe that main_a is in fact lacking the unneeded symbols from b.o. That is, the linker did not suck in the contents of b.o within the archive lib.a because none of the symbols from b.cc were referenced.
You can use ar to create .a file (static library) from .o files (object files)
See man ar for details.
I believe an .a file is an archive that can contain multiple object files.