Conditionally finding dependencies of shared library in CMake - linux

In Linux I have a shared library somelib.so, which could be optionally compiled against several other shared libs, say, dep1 and dep2. Now I'm writing a client application which uses somelib, but I don't now in advance if somelib was compiled with dep1 and dep2 or not until I get a linker error.
Is there a way to find this out using CMake? I need something like
IF somelib DEPEND ON dep1 THEN...

... client application which uses somelib, but I don't now in advance
if somelib was compiled with dep1 and dep2 ... I need something like
IF somelib DEPEND ON dep1 THEN...
On Linux I believe the way to solve it is using LD linker options -Wl,--exclude-libs,ALL and -Wl,--as-needed.
Always include -ldep1 and -ldep2 as library options. Then use -Wl,--as-needed to exclude the libraries if unneeded.
If I recall correctly, this trick dates back 20 or 30 years or so for the math library -lm. Sometimes math symbols were included in glibc and other times they were included in -lm. So you always linked against -lm and allowed the linker to discard the -lm library with -Wl,--as-needed.
In fact the ld(1) man page says to push and pop state when using the trick:
One target for this option are specifications for pkg-config.
When used with the --libs option all possibly needed libraries
are listed and then possibly linked with all the time. It is
better to return something as follows:
-Wl,--push-state,--as-needed -libone -libtwo -Wl,--pop-state
-Wl,--exclude-libs,ALL is an option to keep you from re-exporting symbols from -ldep1 and -ldep2. If the libraries are not used then you should not need -Wl,--exclude-libs,ALL.
I believe the two CMake settings for a static library and shared object when building somelib.so are:
set(OUR_LINKER_FLAGS "-Wl,--exclude-libs,ALL -Wl,--as-needed -ldep1 -ldep2")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${OUR_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${OUR_LINKER_FLAGS}")
Also see ld(1) man page, CMAKE_MODULE_LINKER_FLAGS and CMAKE_SHARED_LINKER_FLAGS in the CMake docs. You might also be interested in CMAKE_EXE_LINKER_FLAGS if you are building executables.

Related

Translating address to function name

Say I have an address acquired by __builtin_return_address(0).
Sometime later I want to translate it to a coreesponding function name.
There's dladdr(3) which works only for dynamic libraries.
Is there any way to receive function of any symbol (maybe by libunwind, backrace_symbol() etc.)?
Compile all your code (and perhaps even some shared libraries that you use) with debug info (-g). Notice that GCC enables to use both -g and some optimization flag like -O2 (of course, in that case, the debug info is "approximate"). So you can compile code with gcc -Wall -g -O2 etc....
Then use perhaps Ian Taylor's libbacktrace which is included in recent versions of GCC.
BTW, dladdr or backtrace_symbol might also work (but I recommend using libbacktrace because it is parsing DWARF info). And dladdr(3) does work on symbols from the executable itself. You may need to link your executable with -rdynamic flag.
Notice also that static symbols (notably  static functions) "don't really exist" in the ELF executable (only global symbols are kept in it) so dladdr cannot give them. Be also aware of the visibility function attribute and pragma.

Weak symbols, shared libraries and dlopen

I have a binary with a weak symbol that I want to be able to link at runtime with a run dependent shared library.
$nm testrun
...
w basic2.test
...
My first test was using a .o file at static linktime, that worked, but I need it to be shared.
So, my second test was getting a shared library with that symbol defined and link it at compile time with -lmy (libmy.so), and this, actually worked as well.
Third step tried not linking at compile time and use ld_preload trick and this did not work.
nm libmy.so
...
00000550 T basic2.test
...
I have really no idea why this particular one does not work, looks like dynamic loader should have enough information to set testruns weak symbol with the one in libmy.so.
My final objective, which I guess will require more work is to load at start a small function that does check for the appropiate symbol with dlsym and sets it there.
Any hint?
It seems that you may need to use LD_DYNAMIC_WEAK along with LD_PRELOAD from the man page:
LD_DYNAMIC_WEAK (glibc since 2.1.91) Allow weak symbols to be overridden (reverting to old glibc behavior). For security reasons, since glibc 2.3.4, LD_DYNAMIC_WEAK is ignored for set-user-ID/set-group-ID binaries.
Note: it could be a typo, but you should use -lmylib.so and not -Lmylib.so

Explanation sought: libtool, automake, shared libraries (and Fortran)

The problem I had is solved. I'm posting this to solicit an explanation as to why the solution actually works. I've gotten great feedback here before.
I have a legacy code base that used a very simplistic build system, and my project is to migrate that to Autotools for customization and, particularly, building shared libraries. The main library is written in C, but must also be linkable from Fortran (for legacy purposes), and is distributed with some test codes in F77. The authors organized the source code into modules...
src_module1/
src_module2/
...
testc/
testf77/
Their built the library lib/libmain.a by compiling code in the src_*/ directories and archiving the objects with ranlib.
My first approach was to build a shared library from each src_*/ separately and "link" all of these into one shared library. Using Autotools, the src_module1/Makefile.am would contain
noinst_LTLIBRARIES = libmodule1.la
libmodule1_la_SOURCES = ...
and so on for the other modules, and finally the lib/Makefile.am would need only:
lib_LTLIBRARIES = libmain.la
libmain_la_SOURCES =
libmain_la_LIBADD = $(top_srcdir)/src_module1/libmodule1.la ...
This seemed to work perfectly. However, when the code in testc/ was compiled and linked against libmain.la, a "symbols not found" error was issued.
Thinking that this was an issue with libtool or shared libraries, I tried building static only, basically changing all .la to .a and all _LTLIBRARIES to _LIBRARIES. Same problem. This time, however, noticing the error "ranlib: warning for library: libmain.a the table of contents is empty (no object file members in the library define global symbols)" when trying to link libmain.a itself.
The solution that I found seems like a hack. I did not build Makefiles for any of the src_*/ directories, but instead used only for the lib/ directory and its Makefile.am had the lines:
lib_LTLIBRARIES = libmain.la
libmain_la_SOURCES = [all sources from all ../src_modules/ ]
This worked. The compiled programs in testc/ linked against libmain.la without issue. One of the "modules" is a set of Fortran bindings that wrap other C functions in the library. Even the Fortran codes in testf77/ linked against libmain.la properly.
Could someone carefully explain what happens when libtool builds a shared library? Or even when building a static library? Why is it that several static libraries can't be linked together to make one static library? Why are symbols only available when libtool/ranlib builds the library "from sources"? And what about installing a shared/static library, i.e. moving it to the /usr/local/lib --- what happens there? The Wikipedia article on static and shared libraries isn't really detailed enough for me.
I do appreciate all efforts to make sense of my longwinded question.
What you first tried ought to work. I am using this kind of setup all the time (in a C++ context). It's also documented, and part of the Automake test suite (although maybe not with Fortran).
A libtool library that is not installable, i.e., one declared with noinst_LTLIBRARIES, is called a libtool convenience library. That noinst_ makes a big difference in what is built. Even if Libtool is configured to build shared libraries, a libtool convenience library is not actually a shared library: it is just a set of object files (compiled as PIC so that they can be latter be used in a shared library) stored in an archive. You can use a libtool convenience library anywhere using this set of objects would make sense, e.g., to build a shared library.
When multiple libtool convenience libraries are LIBADDed to an installable libtool library (such as your libmain.la), Libtool has to unpack the archives containing the objects of each convenience library and link them into the final library.
There is a trap that is worth noting here: when building a shared library out of
convenience libraries, if the _SOURCES variable is empty Automake does not know which linker to use and default to the C linker. If you want to trick Automake into using the linking rule for some specific language, you can declare a nodist_EXTRA_..._SOURCES source file that do not have to exist. (See the Libtool Convenience Libraries section of the Automake manual for an example.)
Maybe that was your problem? If you have some Fortran files in the sources of some of your modules (your description suggests these are only C files), the Fortran linker will be used to build libmain.la only if a Fortran file appears in the source files declared for that libtool library. And the C linker will be used when libmain_la_SOURCES is empty.
Otherwise, I have no idea why it didn't work.
There is an small error in your example:
libmain_la_LIBADD = $(top_srcdir)/src_module1/libmodule1.la
should be
libmain_la_LIBADD = $(top_builddir)/src_module1/libmodule1.la
because the library is not created in the source directory. However I assume this is just a typo, and you won't see the difference unless you do a VPATH build or run make distcheck.
Your second try, using _LIBRARIES without Libtool is not expected to work.
_LIBRARIES can only be used to declare static archives, and in this case _LIBADD may only contain object files, not other static archives. Unpacking an archive to reuse its objects into another archive can be tricky to do portably. Automake's answer to this problem has always been: install Libtool and use _LTLIBRARIES (Libtool can be configured to build only static libraries).

making gcc prefer static libs to shared objects when linking?

When linking against libraries using the -l option (say -lfoo), gcc will prefer a shared object to a static library if both are found (will prefer libfoo.so to libfoo.a). Is there a way to make gcc prefer the static library, if both are found?
The issue I'm trying to solve is the following: I'm creating a plugin for an application (the flight simulator called X-Plane), with the following constraints:
the plugin is to be in the form of a 32 bit shared object, even when running on a 64 bit system
the running environment does not provide a convenient way to load shared objects which are not in the 'normal' locations, say /usr/lib or /usr/lib32:
one cannot expect the user to set LD_PRELOAD or LD_LIBRARY_PATH to find shared objects shipped with my plugin
the X-Plane running environment would not add my plugins directory to ``LD_LIBRARY_PATH, before dynamically loading the plugin shared object, which would allow me to ship all my required shared objects alongside my plugin shared object
one cannot expect 64 bit users to install 32 bit shared objects that are non-trivial (say, are not included in the ia32-libs package on ubuntu)
to solve the above constraints, a possible solution is to link the generated shared object against static, 32 bit versions of all non-trivial libraries used. but, when installing such libraries, usually both static and dynamic versions are installed, and thus gcc will always link against the shared object instead of the static library.
of course, moving / removing / deleting the shared objects in question, and just leaving the static libraries in say /usr/lib32, is a work-around, but it is not a nice one
note:
yes, I did read up on how to link shared objects & libraries, and I'm not trying to creatae a 'totally statically linked shared object'
yes, I tried -Wl,-static -lfoo -Wl,-Bdynamic, but didn't bring the expected results
yes, I tried -l:libfoo.a as well, but this didn't bring the expected results either
You can specify the full path to the static libs without the -l flag to link with those.
gcc ... source.c ... /usr/lib32/libmysuperlib.a ...
Just add the .a file to the link line without -l as if it were a .o file.
It's dated, but may work: http://www.network-theory.co.uk/docs/gccintro/gccintro_25.html
(almost end of the page)
"As noted earlier, it is also possible to link directly with individual library files by specifying the full path to the library on the command line."

VC++ 2010 wants to link boost libararies i didn't even specify

I'm trying to build my application with MSVC 2010 instead of GCC. With GCC everything works fine. My app uses boost_system and boost_thread libraries.
I built boost with VC2010 in "system" layout, that means the libraries are named just libboost_system.lib (and not libboost_system_compiler_threading_version_wtf_snafu.lib)
The libs reside in C:\Boost\lib,
the Makefile specifies
LFLAGS = /NOLOGO /INCREMENTAL:NO /SUBSYSTEM:CONSOLE
LIBS = /LIBPATH:C:/Boost/lib libboost_system.lib libboost_thread.lib Ws2_32.lib
when invoking nmake it compiles, but when trying to link it quits with
LINK : fatal error LNK1104: cannot open file 'libboost_date_time-vc100-mt-1_43.lib
I mean seriously, WTF? I told it to link libboost_systen.lib and libboost_thread.lib how come it tries to link libboost_data_time and why does it assume I built the libs in "tagged" layout??
How can I stop MSVC trying to be smart and guess what I might have wanted to link?
Thanks,
Philipp
This is a feature of the Boost libs with compatible compilers for automatic linking.
(Those convoluted library names cover the myriad of threading and linking options that are available on the platform; there are good reasons to use that convention on Windows...)
More information here:
http://www.boost.org/doc/libs/1_33_1/more/getting_started.html#auto-link
I can't find a page for a more recent version, but I believe the BOOST_ALL_NO_LIB and related options are all still valid in 1.43.
Assuming you are auto-linking (i.e. you've defined BOOST_ALL_DYN_LINK or library specific equivalents).
For layout 'system' you have to define the preprocessor macro:
BOOST_AUTO_LINK_NOMANGLE
to link to the correct library names.
For layout 'tagged' you have to define the preprocessor macro:
BOOST_AUTO_LINK_TAGGED
to link to the correct library names.
I don't know if you could do this override for some libraries and keep the default for others. That would be a very cumbersome setup I'd imagine.

Resources