There is library which is compiled against -lyaml. But libyaml.so is not getting listed as dependency by ldd. Build is happening successfully using autoconf tool chain.
$ nm libxxxx.so | grep -i yaml
U yaml_document_delete
U yaml_document_get_node
U yaml_parser_delete
U yaml_parser_initialize
U yaml_parser_load
U yaml_parser_set_input_file
$ readelf -d libxxxx.so
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000e (SONAME) Library soname: [libxxxx.so.0]
There is another shared library which depends depend upon libxxxx.so.
$ ldd lib/libxxxx1.so
libzmq.so.5 => /usr/lib/x86_64-linux-gnu/libzmq.so.5 (0x00007fd45e072000)
libxmaapi.so.0 =>
When I am linking my executable with libxxxx1.so, it is giving undefined symbols error. The question is how do I link against library not found in dependency tree?
This question provides approaches to ignore the problem.
Linking with dynamic library with dependencies
The one approach which I found is disabling optimization using the gcc flag -Wl,--no-as-needed. Since I am already linking using -lyaml, symbols are getting resolved. It works but not efficient.
Related
I am getting very confused trying to build a simple C++ library using Android NDK 23 (23.1.7779620). I am using CMake and this is a very simple program:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(mf)
add_library(mf lib.cpp)
// lib.hpp
#pragma once
#include <string>
std::string foo(std::string);
// lib.cpp
#include "lib.hpp"
std::string foo(std::string str) {
return std::string{"test"} + str;
}
This is the command line to build:
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DANDROID_STL=c++_shared -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-29 -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake ..
cmake --build . -v
The first problem is that I was expecting to link against libc++.so and not libc++_shared.so. What is the difference between them? I read this article. But still is not explained the difference betweend libc++ and libc++_shared
The second problem is even worst, it seems I am using libstdc++!
The 3rd point, I was thinking that the c++ implementation of clang was under the namespace std::__1 but I cannot find anything like that.
I know libc++_shared is used because of this command:
$ readelf -d libmf.so
Dynamic section at offset 0x76e0 contains 26 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libm.so]
0x0000000000000001 (NEEDED) Shared library: [libc++_shared.so]
0x0000000000000001 (NEEDED) Shared library: [libdl.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so]
0x000000000000000e (SONAME) Library soname: [libmf.so]
Running nm it seem I am using symbols from libstdc++:
$ nm -gDC libmf.so | grep '__ndk1'
0000000000003af0 T foo(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >)
U std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >::append(char const*, unsigned long)
$ nm -gDC libmf.so | grep '__1'
$
Update
In this post is explained the difference between libc++.so and libc++_shared.so
By passing -DANDROID_STL=c++_shared to the CMake invocation you explicitly asked for the shared runtime as opposed to the default runtime.
As explained in the documentation, the rules are simple:
if all your native code is in a single library, use the static libc++ (the default) such that unused code can be removed and you have the smallest possible application package.
As soon as you include an extra library – either because you include a precompiled library from somewhere else or you include an Android AAR file that happens to include native code – you must switch to the shared runtime.
The rationale for the rules is simple: the C++ runtime has certain global data structures that must be initialized once and must only exist once in memory. If you were accidentally to load two libraries that both link the C++ runtime statically, you have (for instance) two conflicting memory allocators.
This will result in crashes when you free or delete memory allocated by the other library, or if you pass a C++ STL object like std::string across library boundaries.
For completeness, in older NDKs libstdc++ (the GNU C++ runtime) was also included in the NDK, but as of NDK r18 that is no longer the case.
I'm testing a somewhat non-conventional project layout and rake as make utility. There is a rule to compile binaries from source files in different directories and link them with a shared library. This rule is run from the root directory of the project. For instance the rule does this:
clang -I libs/ -o tests/sourcefile2 tests/sourcefile2.c shared_libs/libFoo.so
And as a result I get the full path shared_libs/libFoo.so in the binary:
readelf -d tests/sourcefile2
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [shared_libs/libFoo.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
...
I would like to change it to just 'libFoo.so' like this:
readelf -d tests/sourcefile2
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libFoo.so]
...
Then I could set RPATH for dynamic linker as I want and it would give some flexibility. But I cannot find the corresponding option or similar example. Could you suggest how to handle this? Should I just use a temporary directory for the build, copy everything and compile there?
Not sure if it will help you. But when I try compile some shit and I don't know what flags. I use pkg-config.
For example, to compile a program which uses Xlib
pkg-config -cflags -libs x11
and the output is the following
-I/usr/X11R7/include -D_REENTRANT -Wl,-rpath,/usr/X11R7/lib -L/usr/X11R7/lib -lX11
Note this vary on systems, for example NetBSD forces me to link it with rpath, and there are optional arguments in this output.
So I copy the output of pkg-config and it compiles.
if If you use 'ld' as your linker you should be able to use "-Wl,-soname ".
I make a program using a dynamic library, libexample.so. The dynamic library depends on another dynamic library, libtool.so.
It looks linker succeeded linking the libexample.so because of message from gcc.
Building target: libexample.so
Invoking: GCC C++ Linker
g++ -L/home/takehiro/Documents/documents/code/lib/tool -shared -o "libexample.so" ./classes/example.o ./classes/example_template.o ./classes/example_test.o ./classes/impl.o -ltool
Finished building target: libexample.so
cp libexample.so /home/takehiro/Documents/documents/code/lib/example
However, it failed to link it with the libtool.so.
ldd /home/takehiro/Documents/documents/code/lib/example/libexample.so
...
libtool.so => not found
...
I checked existence of the libtool.so under /home/takehiro/Documents/documents/code/lib/tool which is pointed by -L optoin at above linker by
ls /home/takehiro/Documents/documents/code/lib/tool
libtool.so
This is the first time to use a dynamic library depending another dynamic library. So I am so confused. Is it normal or malfunction? Why it cannot link them?
Does someone have a suggestion or a solution to me? I am very glad it.
Thank you very much.
All that the -L option does is tell the linker where the shared library is, at link time.
This does not have any effect on where the runtime loader searches for shared libraries. That's why the shared library fails to be loaded at runtime.
You also need to pass the -rpath option to the linker, when you're linking your shared library, in order to set the RPATH attribute on the shared library, that specifies where its dependencies are to be searched for. Something like
g++ -L/home/takehiro/Documents/documents/code/lib/tool \
-Wl,-rpath=/home/takehiro/Documents/documents/code/lib/tool \
... remaining options
Apart from a longer compile time, is there any downside to linking against an unused library?
for example, is there any difference in the executable of a program that is compiled one of two ways:
g++ -o main main.cpp
g++ -o main main.cpp -llib1 -llib2 -llib3 -lmore
*no library files were actually needed to build main.
I believe it makes no difference because the file sizes are the same, but I'm asking for confirmation.
It depends.
If liblib1.a, liblib2.a, and liblib3.a are static libraries, and no symbols are used from them, then there will be no difference.
If liblib1.so, liblib2.so, or liblib3.so are shared libraries, then they will be loaded at runtime whether or not they are used. You can use the linker flag --as-needed to change this behavior, and this flag is recommended.
To check which shared libraries your binary directly loads at runtime, on an ELF system you can use readelf.
$ cat main.c
int main()
{
return 0;
}
$ gcc main.c
$ readelf -d a.out | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
$ gcc -lpng main.c
$ readelf -d a.out | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libpng12.so.0]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
You can see that on my system, -lpng links against libpng12.so.0, whether or not symbols from it are actually used. The --as-needed linker flag fixes this:
$ gcc -Wl,--as-needed -lpng main.c
$ readelf -d a.out | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
Notes
The --as-needed flag must be specified before the libraries. It only affects libraries which appear after it. So gcc -lpng -Wl,--as-needed doesn't work.
The ldd command lists not only the libraries your binary directly links against, but also all the indirect dependencies. This can change depending on how those libraries were compiled. Only readelf will show you your direct dependencies, and only ldd will show you indirect dependencies.
It depends whether you are linking static libraries or shared libraries. If you are linking static libraries then the executable size would increase with each addition. Linking to shared libraries, doesn't not increases executable size greatly, only library symbols are added.
Absolutely yes. The downside is that others (or you in the future) will assume the libraries are needed for some reason. Most people will not take the time to pare down a program's dependencies, and so the list of them grows and grows.
The cost has nothing to do with the compiled code, but everything to do with maintaining and porting programs.
There are some really good answers above. A further note would be "what difference does it really make". Already mentioned is the cost of maintenance (e.g. problems when someone installs a fresh operating system, which doesn't have Lib3, so the user has to go find lib3 somewhere and install it, and because lib3 also needs lib17 which you also isn't installed, it adds more work for the user).
But also, when you load the binary, if you have linked against shared libraries that aren't actually used, the system will still go look for those libraries, and refuse to load if they are not present - this adds time, and install nightmare.
Once the code is loaded, it should have no additional runtime penalty.
Having said that, there are sometimes arguments for linking against unused libraries. Say your code has an option USE_FOO, where the FOO feature is only included based on some arbitrary choice when building (e.g. "is this on Linux kernel > 3.0" or "Does the system have a fancy graphics card"), and FOO uses Lib1 to do it's business, it can make the build system (makefile or similar) a little simpler to always link against lib1, even if you don't actually need it when USE_FOO is not set.
But in general, don't link against libraries not needed. It causes more dependencies, and that's never a good thing.
I have just built a shared lib on Ubuntu, and when I attempt to use the function, the application that loads the library is reporting 'xxx' symbol not found.
I want to check (i.e. list) the functions that are exported by my library so I can investigate this issue further.
Relevant details:
OS: Ubuntu 9.10
compiler: gcc 4.4.1
linker: GNU ld 2.20
Try the nm utility.
GNU nm lists the symbols from object
files objfile.... If no object files
are listed as arguments, nm assumes
the file a.out. [reference]
nm -D -C -g <library>
works well too.
Is your shared library in the library load path or in the application's run-time search path? It sounds like the dynamic linker can't find your library. Try running ldd on your application to see if the library can be found at run-time, e.g.:
$ ldd /usr/bin/less
linux-gate.so.1 => (0x0072a000)
libncurses.so.5 => /lib/libncurses.so.5 (0x00c68000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x007c7000)
libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0x00286000)
/lib/ld-linux.so.2 (0x002a1000)
See the ld.so(8) man page for additional details on library search paths.