Different ways to specify libraries to gcc/g++ - gcc

I'd be curious to understand if there's any substantial difference in specifying libraries (both shared and static) to gcc/g++ in the two following ways (CC can be g++ or gcc)
CC -o output_executable /path/to/my/libstatic.a /path/to/my/libshared.so source1.cpp source2.cpp ... sourceN.cpp
vs
CC -o output_executable -L/path/to/my/libs -lstatic -lshared source1.cpp source2.cpp ... sourceN.cpp
I can only see a major difference being that passing directly the fully-specified library name would make for a greater control in choosing static or dynamic versions, but I suspect there's something else going on that can have side effects on how the executable is built or will behave at runtime, am I right?
Andrea.

Ok, I can answer myself basing on some experiments and a deeper reading of gcc documentation:
From gcc documentation: http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
[...] The linker handles an archive file by scanning through it for members which define symbols that have so far been referenced but not defined. But if the file that is found is an ordinary object file, it is linked in the usual fashion. The only difference between using an -l option and specifying a file name is that -l surrounds library with lib' and.a' and searches several directories
This actually answers also to the related doubt about the 3rd option of directly specifying object files on the gcc command line (i.e. in that case all the code in the object files will become part of the final executable, while using archives, only the object files that are really needed will be pulled in).

Related

What are "nosys", "nano", "rdimon" terms when using ARM GCC?

I am learning to write ARM code using the GCC toolchain. I've run into a few GCC options that I cannot find documentation for. Could someone please help explain what they do?
-specs=nosys.specs
-specs=nano.specs
-specs=rdimon.specs
-lnosys
How do -specs=nosys.specs and -lnosys relate? Do you use them together, or are they exclusive of each other, or something else?
And nano, I've gathered to imply using the newlib-nano library. I've seen this used in conjunction with -lm and -lc. Does this just give you the standard libc and libm functions?
What does rdimon stand for? I understand it is for "semihosting", which means using the host IO somehow. Does this mean I can printf to the host console? I can find no documentation on how to actually use this.
If there is a source of truth for all of this somewhere that I haven't found, please let me know.
Thanks for any help on clarifying.
Gcc uses specs-strings, which control which subprocesses to run and what parameters it shall pass to them. The behavior defined by the spec-strings can be overridden using spec-files, whose purpose and syntax is documented here: https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html
Looking at these spec files in the lib folder of the gcc tool chain (e.g. /usr/lib/arm-none-eabi/lib) we can see that the mentioned spec files define which standard library is to be used by the linker.
For example, nosys.specs just defines that system calls should be implemented as stubs that return errors when called (-lnosys). The choice of libc in this case depends on whether nano should be used. With %G the libgcc spec-string is processed, which defines the parameters passed to the linker.
nosys.specs:
%rename link_gcc_c_sequence nosys_link_gcc_c_sequence
*nosys_libgloss:
-lnosys
*nosys_libc:
%{!specs=nano.specs:-lc} %{specs=nano.specs:-lc_nano}
*link_gcc_c_sequence:
%(nosys_link_gcc_c_sequence) --start-group %G %(nosys_libc) %(nosys_libgloss) --end-group
nano.specs defines the system include path and library parameters to use newlib-nano. The spec file contains replacements for -lc and others to nano equivalents, e.g. -lc_nano. So using it in conjunction with these will make gcc still pass nano libaries to the linker.
Using rdimon.specs, -lrdimon is passed as the libgloss part of the standard library. This basically means that you can use system calls (and also printf), but this relies on a debugger being attached, and the CPU may crash if no debugger is present.

The -l option in GCC

I have just begun reading the book Advanced Programming in Unix Environment and try to compile the first example code, just the same as in this question.
Although the problem for the compilation is solved using the command,
gcc -o myls myls.c -I SCADDRESS/include/ -L SCADDRESS/lib/ -lapue
I looked it up in the GCC manual, but what does the GCC option -lxxx mean? Where xxx stands for the base name of a header file (in this case, it's apue.h). According to the manual, xxx should be some library files, either end with .so for shared object files, or with .a for static libraries.
This is documented in ยง2.13 "Options for Linking" in the GCC manual:
-llibrary
Search the library named library when linking.
It makes a difference where in the command you write this option; the
linker searches processes libraries and object files in the order they
are specified. Thus, `foo.o -lz bar.o' searches library `z'
after file `foo.o' but before `bar.o'. If `bar.o' refers
to functions in `z', those functions may not be loaded.
The linker searches a standard list of directories for the library,
which is actually a file named `liblibrary.a'. The linker then uses this file as if it had been specified precisely by name.
The directories searched include several standard system directories
plus any that you specify with `-L'.
Normally the files found this way are library files--archive files
whose members are object files. The linker handles an archive file by
scanning through it for members which define symbols that have so far
been referenced but not defined. But if the file that is found is an
ordinary object file, it is linked in the usual fashion. The only
difference between using an `-l' option and specifying a file name is that `-l' surrounds library with `lib' and `.a'
and searches several directories.
The -l option tells GCC to link in the specified library. In this case, the library is apue, and that it happens to line up with the name of a header file is just how the apue coders designed their project.
In reality, the -l option has nothing to do with header files. Like cas says in the comments, read the man page; it'll give you much more information.

Two ways of linking to static libraries

Here are a couple of ways to use functions from a static library, built with ar (i.e. libSOMTEHING.a):
ld -o result myapp.o -Lpath/to/library -lname
ld -o result myapp.o path/to/library/libname.a
Since we omit any dynamic libraries from the command line, this should build a static executable.
What are the differences? For example, are the whole libraries linked in the executable, or just the needed functions? In the second example, does switching the places of the lib and the object file matter?
(PS: some non-GNU ld linkers require all options like -o to be before the first non-option filename, in which case they'd only accept -L... -lname before myapp.o)
In the first line, a search for a dynamic library (libname.so) occurs before the static library (libname.a) within a directory. Also, the standard lib path is also searched for libname.*, not just /path/to/library.
From "man ld"
On systems which support shared libraries, ld may also search for
files other than libnamespec.a. Specifically, on ELF and SunOS
systems, ld will search a directory for a library called
libnamespec.so before searching for one called libnamespec.a. (By
convention, a ".so" extension indicates a shared library.)
The second line forces the linker to use the static library at path/to/lib.
If there is no dynamic library built (libname.so), and the only library available is path/to/library/libname.a, then the two lines will produce the same "result" binary.

Is that possible to link to different objects during compilation?

Say I have two versions of a library which reside in folder "V1" and "V2", and I have two C files: "v1.c" and "v2.c", where "v1.c" will use library "V1", and "v2.c" will use library "V2". Note that "V1" and "V2" has the same interface. I tried:
g++ -c v1.c -o v1.o -I${V1}include
g++ -c v2.c -o v2.o -I${V2}include
g++ main.c -L${V1}lib v1.o -L${V2}lib v2.o -lsomething
Note that I provided 2 library paths before the 2 object files in the last linking step. Apparently it will not do what I expected, but I showed as it just to make my intention clear. Thanks for any suggestion.
It will use the first found suitable symbol, i.e. if you have a function 'bar' in both libraries, and libraries have the same name, function 'bar' from file which comes first in search will be used.
You can either give different names to symbols in different libraries (which would still have the same name), either give libraries different names.
Although I'm still not sure that renaming symbols will help, since linker could just link against firstly-encountered library and then complain that it doesn't contain the other needed symbol. The most sure way is renaming libraries.
Please comment if something is unclear, I'll try to explain further.

How to force gcc to link like g++?

In this episode of "let's be stupid", we have the following problem: a C++ library has been wrapped with a layer of code that exports its functionality in a way that allows it to be called from C. This results in a separate library that must be linked (along with the original C++ library and some object files specific to the program) into a C program to produce the desired result.
The tricky part is that this is being done in the context of a rigid build system that was built in-house and consists of literally dozens of include makefiles. This system has a separate step for the linking of libraries and object files into the final executable but it insists on using gcc for this step instead of g++ because the program source files all have a .c extension, so the result is a profusion of undefined symbols. If the command line is manually pasted at a prompt and g++ is substituted for gcc, then everything works fine.
There is a well-known (to this build system) make variable that allows flags to be passed to the linking step, and it would be nice if there were some incantation that could be added to this variable that would force gcc to act like g++ (since both are just driver programs).
I have spent quality time with the gcc documentation searching for something that would do this but haven't found anything that looks right, does anybody have suggestions?
Considering such a terrible build system write a wrapper around gcc that exec's gcc or g++ dependent upon the arguments. Replace /usr/bin/gcc with this script, or modify your PATH to use this script in preference to the real binary.
#!/bin/sh
if [ "$1" == "wibble wobble" ]
then
exec /usr/bin/gcc-4.5 $*
else
exec /usr/bin/g++-4.5 $*
fi
The problem is that C linkage produces object files with C name mangling, and that C++ linkage produces object files with C++ name mangling.
Your best bet is to use
extern "C"
before declarations in your C++ builds, and no prefix on your C builds.
You can detect C++ using
#if __cplusplus
Many thanks to bmargulies for his comment on the original question. By comparing the output of running the link line with both gcc and g++ using the -v option and doing a bit of experimenting, I was able to determine that "-lstdc++" was the magic ingredient to add to my linking flags (in the appropriate order relative to other libraries) in order to avoid the problem of undefined symbols.
For those of you who wish to play "let's be stupid" at home, I should note that I have avoided any use of static initialization in the C++ code (as is generally wise), so I wasn't forced to compile the translation unit containing the main() function with g++ as indicated in item 32.1 of FAQ-Lite (http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html).

Resources