Why explicit parameters for static and dynamic linking - c++

I have mostly worked in Windows, and recently I started working in Linux. I have a doubt. I have used Visual Studio as IDE in Windows and used Makefile in Linux.
There are two types of libraries in Windows (VC++), static library (.lib) and DLL. It is quite obvious (isn't it?) if I link with lib file I am using static linking else dynamic linking.
Now when I use g++ compiler, why I need to explicitly mention -Bstatic/-static or Bdynamic/-dynamic flags. Because if file is .a file then I must be using static -linking and if file is .so I am using dynamic linking.

There are times when you want to "force" the compiler to do what it normally wouldn't. In particularly -static is useful when you are building against a library that may not be installed [or not have the same version installed] on another machine where you want your code to run.
the -Bdynamic is useful if you want to have ONE library linked statically, but not EVERY library that your code uses.
e.g. gcc -o myprog myprog.o -Wl,-Bstatic -lspecial -Wl,-Bdynamic
will link myprog using static linking for libspecial (which may be something that isn't widely distributed, for example something you have built yourself)
For general, local development, you don't need either.

In the GNU toolchain, and other Unix compilers, you generally don't specify the full path to a library; you give the linker a flag such as
-lfoo
and let it figure out whether it should link with libfoo.a, libfoo.so, and where these files are located. When only a static library is available, it will link with that.
So, you don't really need to specify -Bstatic except in a few specific cases. Dynamic linking is the default and if you don't want a custom library to be linked dynamically, then just don't build a .so out of it.
Besides, you can explicitly link with a static library by giving the full filename to the linker
gcc -o some_binary main.o libfoo.a
to get a dynamically linked binary with libfoo statically linked in.

I think you've got it backwards. Whether I'm linking with
a dynamic library or with a static one, under Windows, I need
a .lib file; they just aren't generated in the same manner,
and don't contain the same thing. Under Unix, when I link with
a shared object, I link directly against the .so file, and not
against some additional file generated at the same time.
The options -Bstatic and -Bdynamic only come into play when
both a .so and a .a are present, in the same directory; they
tell the linker which one to choose for libraries specified
using the -l option. In Windows, this situation cannot occur;
since you need a .lib for the .dll, you cannot have a .lib
to be statically linked in the same directory.

Because if file is .a file then I must be using static -linking and if file is .so I am using dynamic linking.
These filename "extensions" are only human conventions — there is no reason that they have to be .a and .so respectively. Quite rightly does GCC not force us into that convention.

Related

Misconception about static/implicit linking Vs dynamic/explcit linking

I've recently learnt that static linking and implicit linking are basically the same thing, just different nomenclature. My understanding is that when you statically (implicitely) link to a binary, you are by definition linking against a *.lib (windows) or *.a (linux) file, often using target_link_libraries in cmake. On the other hand when you explicitely link (using LoadLibrary on windows) you are by definition linking to a *.dll file (or *.so on linux) (and there is no corresponding cmake command because all the work is done inside the actual code).
However, in multiple places I've read people referring to statically/implicitely linking to a dll file, which has confused me. Clearly there is a hole in my knowledge somewhere and I was hoping somebody here could plug it.
Edit
Its been pointed out that this question refers mainly to windows, which it does. However, I am currently trying to produce cross platform code so I am still interested on how (or if) these concepts generalise to other platforms.
There are actually 3 different kinds of linking, not 2.
For UNIX:
Link against archive (aka static) library:
gcc main.o libfoo.a
link against dynamic (aka shared) library:
gcc main.o libfoo.so
Link against libdl, which allows you to dlopen arbitrary other shared libraries (which don't need to exist at the time of the link):
gcc main.o -ldl
Both 2 and 3 involve dynamic linker (and are using shared libraries), but to a different extent.
An equivalent exists on Windows: when you link against foo.lib, you are using either 1 or 2, depending on whether foo.lib contains actual code, or refers to foo.dll.
When you use LoadLibrary, you are in case 3.

Linking libraries in c++

I have a C++ file a.cpp with the library dependency in the path /home/name/lib and the name of the library abc.so.
I do the compilation as follows:
g++ a.cpp -L/home/name/lib -labc
This compiles the program with no errors.
However while running the program, I get the ERROR:
./a.out: error while loading shared libraries: libabc.so.0: cannot open shared object file: No such file or directory
However if before running the program, I add the library path as
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/name/lib;
and compile and run now, it works fine.
Why am I not able to link the library by giving it from the g++ command?
Because shared object libraries are linked at runtime - you either need to add the location to the library search path (as you've done), place it somewhere within an already existing path (like /usr/lib), or add a symbolic link to an existing library path that links to the location where it exists.
If you want to compile the library in so there is no runtime dependency, you'll need a static library (which would be abc.a) - note that this has numerous downsides, however (if the library is updated, you'll need to recompile your executable to incorporate that update).
Why am I not able to link the library by giving it from the g++ command?
You are able to link, and you did link the library succesfully. Otherwise you would not be able to build executable (in your case a.out). The problem you mixed 2 different things: linking with shared libraries and loading them at runtime. Loading shared libraries is a pretty complex concept and described pretty well here Program-Library-HOWTO read from 3.2.
You are linking dynamically, is the default behavior with GCC. LD_LIBRARY_PATH is used to specify directories where to look for libraries (is a way of enforce using an specific library), read: Program-Library-HOWTO for more info. There is also an ld option -rpath to specify libraries search path for the binary being compiled (this info is written in the binary and only used for that binary, the LD_LIBRARY_PATH affect other apps using the same library, probably expecting a new or old version).
Linking statically is possible (but a little tricky) and no dependency would be required (but sometimes is not recommended, because prevent the update of the dependent libraries, for example for security reason, in static linking your always are using the versions of the libraries you have when compiled the binary).

Generating single .so from multiple C++ and C object files

Let's say I have a C++ library code, with some definitions wrapped with extern "C" { ... }.
I also have a C library code which uses that C++ library.
What I want to do is to create a single .so file, so that only one call to dlopen should be enough to start using this library.
Here's what I do now: I'm first compiling my C++ library to a .so file with -shared -rdynamic -fPIC. Then I'm compiling my C library to a .so file with same parameters. After that, I have to load C++ library with dload before loading the C library. Otherwise loading fails with a undefined symbol error.
What I want to do is to compile this two libraries into one .so file so that only one call to dload should be enough to use it.
How can I do that?
Thanks in advance.
EDIT: Compiling to .o files and then combining doesn't work for me. Here's what I do:
I compile each file to object file with -fPIC parameter
I link them with clang [list of object files] -shared -rdynamic -fPIC -o libmylib.so
When I try to load, I get undefined symbol: __gxx_personality_v0 error.
EDIT2: Ahh, I forgoto to link it against libstdc++, it works now. Thanks.
The easiest way is to combine them into a single .so file by either combining all object files, or building two static .a libraries and then linking them into a single shared library.
If you really want to keep two .so files, link the first library to the second, as you would with executable. E.g. if libfoo depends on libbar, compile libfoo with -lbar. You'd have to have the dependent libraries in your default library path or in LD_LIBRARY_PATH environment variable.

Can I build a shared library by linking static libraries?

I have a bunch of static libraries (*.a), and I want to build a shared library (*.so) to link against those static libraries (*.a). How can I do so in gcc/g++?
You can (just extract all the .o files and link them with -shared to make a .so), but whether it works, and how well it works, depends on the platform and whether the static library was compiled as position-independent code (PIC). On some platforms (e.g. x86_64), non-PIC code is not valid in shared libraries and will not work (actually I think the linker will refuse to make the .so). On other platforms, non-PIC code will work in shared libraries, but the in-memory copy of the library is not sharable between different programs using it or even different instances of the same program, so it will result in HUGE memory bloat.
I can't see why you couldn't just build the files of your dynamic library to .o files and link with;
gcc -shared *.o -lstaticlib1 -lstaticlib2 -o mylib.so

Should I create .a or .so when packaging my code as a library?

I have a software library and I used to create .a files, so that people can install them and link against them: g++ foo.o -L/path/to -llibrary
But now I often encounter third-party libraries where only .so files are available (instead of .a), and you just link against them without the -l switch, e.g. g++ foo.o /path/to/liblibrary.so.
What are the differences between these solutions? Should I prefer creating .so files for the users of my library?
Typically, libfoo.a is a static library, and libfoo.so is a shared library. You can use the same -L/-l linker options against either a static or shared. Or you can name the full path to the lib with static or shared. Often libraries are built both static and shared to provide application developers the choice of which they want.
All the code needed from a static lib is part of the final executable. This obviously makes it bigger, but it also means it's self-contained. Once it is compiled, you can run your app without the lib.
Code from a shared lib is not part of the executable. There are just some hooks in place to make the executable aware of the name of the lib it needs. In order to run your app, the shared lib has to be present in the lib search path (e.g. $LD_LIBRARY_PATH).
If you have two apps that share the same code, they can each link against a shared lib to keep the binary size down. If you want to upgrade parts of the app without rebuilding the whole thing, shared libs are good for that too.
Good overview of static, shared dynamic and loadable libraries at
http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html
Some features that aren't really called out from comments I've seen so far.
Static linkage (.a/.lib)
Sharing memory between these compilation units is generally ok because they should(?will) all be using the same runtime.
Static linkage means you avoid 'dll hell' but the cost is recompilation to make use of any change at all. static linkage into Shared libraries (.so) can lead to strange results if you have more than 1 such shared library used by the final executable - global variables may exist multiple times and which one is used and when they are initialised can cause an entirely different hell.
The library will be part of the shipped product but obfuscated and not directly usable.
Shared/Dynamic libraries (.so/.dll)
Sharing memory between these compilation units can be hazardous as they may choose to use different runtime. This can mean you provide different Shared/Dynamic libraries based on the debug/release or single/multi threaded or...
Shared libraries (.so) are less prone to 'dll hell' then Dynamic libraries (.dll) as they include options for quite specific versioning.
Compiling against a .so will capture version information internal to the file (hard to fake) so that you get quite specific .so usage. Compiling against the .lib/.dll only gives a basic file name, any versioning is done managed by the developer (using naming or manually loading the library and checking version details by hand)
The library will have to ship with the final product (somebody else can pick it up and use it)
But now I often encounter third-party libraries where only .so files are available [...] and you just link against them without the -l switch, e.g. g++ foo.o /path/to/liblibrary.so.
JFYI, if you link to a shared library which does not have a SONAME set (compare with readelf -a liblibrary.so), you will end up putting the specified path of liblibrary.so into your target object (executable or another shared library), and which is usually undesired, for users have their own ideas of where to put a program and its associated files. The preferred way is to use -L/path/to -llibrary, perhaps together with -Wl,-rpath,/whatever/path/to if this is the final path (such pathing decisions are made by Linux distributions for example).
Should I prefer creating .so files for the users of my library?
If you distribute source code, the user will make the particular choice.