Why does gcc prefer dynamic library to static one during linking process? - c

I compile and link a simple program:
# gcc a.c -pthread
# ldd a.out
linux-vdso.so.1 (0x00007ffc4ddf2000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fbb75e12000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fbb75a6e000)
/lib64/ld-linux-x86-64.so.2 (0x00007fbb76030000)
The program links the shared library. But from gcc manual:
-llibrary
-l library
......
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.
......
It seems the program should link the static library. I find there are both static and dynamic libraries:
# ls -alt /usr/lib/libpthread*
-rw-r--r-- 1 root root 392576 Mar 6 22:06 /usr/lib/libpthread.a
lrwxrwxrwx 1 root root 18 Mar 6 22:06 /usr/lib/libpthread.so.0 -> libpthread-2.25.so
-rw-r--r-- 1 root root 1748 Mar 6 22:06 /usr/lib/libpthread_nonshared.a
-rwxr-xr-x 1 root root 146824 Mar 6 22:06 /usr/lib/libpthread-2.25.so
-rw-r--r-- 1 root root 222 Mar 6 22:06 /usr/lib/libpthread.so
Why does gcc choose the dynamic one? BTW, is there any difference when using -lpthread and pthread as the link option during compiling program?

Related

Shared object creation: dangling symlink using make

I am trying to create a shared library using gcc and make. I have the following section in the Makefile to compile the shared library object:
# The library build step.
lib : $(DHLLOBJS)
$(CC) $(XCFLAGS) $(SCFLAGS)$(SLIB).1 $(INCFLAGS) -o $(LIB_DIR)/$(SLIB).1.0 \
$(DLOPATHS) $(LNKFLAGS)
ln -sf $(LIB_DIR)/$(SLIB).1.0 $(LIB_DIR)/$(SLIB).1
ln -sf $(LIB_DIR)/$(SLIB).1.0 $(LIB_DIR)/$(SLIB)
The above doesn't throw any compilation errors or file system errors but the symlinks are described as dangling as shown by a chmod command:
$ sudo chmod 0755 ../lib/*
chmod: cannot operate on dangling symlink '../lib/libdhlim.so'
chmod: cannot operate on dangling symlink '../lib/libdhlim.so.1'
and the ls command output below shows the lines 5 and 6 in red:
$ ls -la lib/
total 29
drwxrwxrwx 1 root root 376 Jul 5 21:13 .
drwxrwxrwx 1 root root 4096 Jul 5 21:13 ..
lrwxrwxrwx 1 root root 21 Jul 5 21:13 libdhlim.so -> ./lib/libdhlim.so.1.0
lrwxrwxrwx 1 root root 21 Jul 5 21:13 libdhlim.so.1 -> ./lib/libdhlim.so.1.0
-rwxrwxrwx 1 root root 23792 Jul 5 21:13 libdhlim.so.1.0
When I run the same set of commands manually, they work fine. Is there something I am doing wrong here?
The problem is that you use relative paths but don't create the links with the ln option -r.
Try these as the last two lines:
ln -sfr $(LIB_DIR)/$(SLIB).1.0 $(LIB_DIR)/$(SLIB).1
ln -sfr $(LIB_DIR)/$(SLIB).1.0 $(LIB_DIR)/$(SLIB)
-r, --relative
with -s, create links relative to link location

How to create an executable that links to a static library using a Makefile?

I'm new to C, and Makefiles are giving me a hard time. Within the Makefile, I want to make an executable that links to a static library. My understanding is that to generate an executable from test.c located in src/project the command would be gcc src/project/test.c -o test, and this executable would be named test. If I wanted to have the executable also link with a static library, lib.a how would I do that?
First of all, lib.a is not a canonically "valid" static library filename, library filenames should start with lib and continue with the actual name of the library, e.g. libsomething.a. You would then link such library with -lsomething, assuming it is in the appropriate system directories. If not, you can add -Lpath/to/directory to make the linker also look into path/to/directory for libsomething.a. See also: Order in which library directories are searched and linked. Alternatively, in case of a static library you could also add the library directly to the GCC command line: gcc prog.c libsomething.a.
In a very basic Makefile I would do something like this:
test: src/project/test.c path/to/libsomething.a
gcc $^ -o $#
If I wanted to have the executable also link with a static library, lib.a how would I do that?
Short answer is: just include the library in the gcc command using
gcc src/project/test.c -o test libstuff.a
Or use
gcc src/project/test.c -o test -lstuff -Llibfolder
-L adds the libfolder to the list of folders where search for libraries are done. There is a folder search sequence for libraries similar to what happens with #include processing.
back to make
I will show a minimal example of how to build and use an static library in C and manage its use via a very short makefile, under Linux Ubuntu 20.
This is minimal and just for demonstration purposes. There are better ways to write this but I hope that writing this way will make easier for you to follow the logic.
Note: ar is the archiver in Linux, just like LIB in Windows. The program that manages creation of libraries.
Example
Take a folder with these 4 files
Makefile myLib.c myLib.h testing.c
We want to build a library libmyLib.a from myLib.c and use it in testing
The C sources
For the library:
// myLib.h
int twice(int);
// myLib.c
#include <stdio.h>
int twice(int value) { return value + value; }
The test program
// testing.c
#include <stdio.h>
#include "myLib.h"
int main(void)
{ int x = 42;
printf("x = %d, twice(%d) = %d\n", x, x, twice(x) );
return 0;
}
test output
testing just calls twice(42) and outputs 84
x = 42, twice(42) = 84
using the makefile
We want to type make and have libmyLib.a built, testing.c compiled and testing generated.
Something like (with make output suppressed by now):
so_user#DSK-2009:~/projects/so0802$ ls -ltr
total 32
-rw-r--r-- 1 so_user so_user 266 Aug 2 17:46 Makefile
-rw-r--r-- 1 so_user so_user 26 Aug 2 18:23 myLib.h
-rw-r--r-- 1 so_user so_user 155 Aug 2 18:23 testing.c
-rw-r--r-- 1 so_user so_user 79 Aug 2 18:23 myLib.c
so_user#DSK-2009:~/projects/so0802$ make
// supressed output //
so_user#DSK-2009:~/projects/so0802$ ls -ltr
total 44
-rw-r--r-- 1 so_user so_user 266 Aug 2 17:46 Makefile
-rw-r--r-- 1 so_user so_user 26 Aug 2 18:23 myLib.h
-rw-r--r-- 1 so_user so_user 155 Aug 2 18:23 testing.c
-rw-r--r-- 1 so_user so_user 79 Aug 2 18:23 myLib.c
-rw-r--r-- 1 so_user so_user 1792 Aug 2 18:42 testing.o
-rw-r--r-- 1 so_user so_user 1368 Aug 2 18:42 myLib.o
-rw-r--r-- 1 so_user so_user 1510 Aug 2 18:42 libmyLib.a
-rwxr-xr-x 1 so_user so_user 16760 Aug 2 18:42 testing
so_user#DSK-2009:~/projects/so0802$ ./testing
x = 42, twice(42) = 84
so_user#DSK-2009:~/projects/so0802$
make is an absurdly clever program that takes into account the last modification time of the files to, yes, make things up to date. make is based on so called makefiles, whose name defaults to Makefile. In the makefile things to be updated are called targets.
A makefile, even for a short project, can be a complex thing. But is always easier than not using one.
what would a make run do?
you can present the so called targets to make. If you just type make the program will search for a file named Makefile and inside the file for a target named all.
The first command below only updates the library, while the second will try the target all
make libMylib.a
make
make -n
You can always try -n and make will list what the program will do to update the targets.
Following the example above...
so_user#DSK-2009:~/projects/so0802$ make -n
make: Nothing to be done for 'all'.
so_user#DSK-2009:~/projects/so0802$
As the targets are all updated. Now suppose testing.c is changed:
so_user#DSK-2009:~/projects/so0802$ touch testing.c
so_user#DSK-2009:~/projects/so0802$ ls -ltr
total 44
-rw-r--r-- 1 so_user so_user 266 Aug 2 17:46 Makefile
-rw-r--r-- 1 so_user so_user 26 Aug 2 18:23 myLib.h
-rw-r--r-- 1 so_user so_user 79 Aug 2 18:23 myLib.c
-rw-r--r-- 1 so_user so_user 1792 Aug 2 18:42 testing.o
-rw-r--r-- 1 so_user so_user 1368 Aug 2 18:42 myLib.o
-rw-r--r-- 1 so_user so_user 1510 Aug 2 18:42 libmyLib.a
-rwxr-xr-x 1 so_user so_user 16760 Aug 2 18:42 testing
-rw-r--r-- 1 so_user so_user 155 Aug 2 18:57 testing.c
so_user#DSK-2009:~/projects/so0802$ make -n
gcc -c -Wall testing.c
gcc -o testing testing.o libmyLib.a
so_user#DSK-2009:~/projects/so0802$
And you see that, as testing.c is newer, but as the library has not changed, we need to compile the program and link it with the library:
-rw-r--r-- 1 toninho toninho 266 Aug 2 17:46 Makefile
-rw-r--r-- 1 toninho toninho 26 Aug 2 18:23 myLib.h
-rw-r--r-- 1 toninho toninho 79 Aug 2 18:23 myLib.c
-rw-r--r-- 1 toninho toninho 1368 Aug 2 18:42 myLib.o
-rw-r--r-- 1 toninho toninho 1510 Aug 2 18:42 libmyLib.a
-rw-r--r-- 1 toninho toninho 155 Aug 2 18:57 testing.c
-rw-r--r-- 1 toninho toninho 1792 Aug 2 19:00 testing.o
-rwxr-xr-x 1 toninho toninho 16760 Aug 2 19:00 testing
But now we change myLib.c and try make -n:
so_user#DSK-2009:~/projects/so0802$ touch myLib.c
so_user#DSK-2009:~/projects/so0802$ make -n
gcc -c -Wall testing.c
gcc -c -Wall myLib.c
ar rcs libmyLib.a myLib.o
gcc -o testing testing.o libmyLib.a
so_user#DSK-2009:~/projects/so0802$
since the library changed, the header file could have also changed so we need to compile testing.c also. And call ar to rebuild the library, before generating a new testing executable.
The makefile used here
all: testing
clean:
rm *.o
rm *.a
rm testing
testing: testing.o libmyLib.a
gcc -o testing testing.o libmyLib.a
testing.o: testing.c myLib.c myLib.h
gcc -c -Wall testing.c
myLib.o: myLib.c myLib.h
gcc -c -Wall myLib.c
libmyLib.a: myLib.o
ar rcs libmyLib.a myLib.o
I hope it is a bit clear how things go with make. Fell free to ask back about this.
the things before : are the targets
the clean target is usual, and you see here it just removes things
the things listed after a target are called dependencies, and it makes sense: if any of the dependencies are newer than the target the commands below the line of dependencies are run.
make is deeply recursive in the search of targets to update

Why I am getting libhdf5_hl not loaded error during executing the HDF5 example code?

I am trying to executing the c program to execute the HDF5 basic code. That is here below.
/*
* This example illustrates how to create a dataset that is a 4 x 6
* array. It is used in the HDF5 Tutorial.
*/
#include "hdf5.h"
#define FILE "dset.h5"
int main() {
hid_t file_id, dataset_id, dataspace_id; /* identifiers */
hsize_t dims[2];
herr_t status;
/* Create a new file using default properties. */
file_id = H5Fcreate(FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
/* Create the data space for the dataset. */
dims[0] = 4;
dims[1] = 6;
dataspace_id = H5Screate_simple(2, dims, NULL);
/* Create the dataset. */
dataset_id = H5Dcreate2(file_id, "/dset", H5T_STD_I32BE, dataspace_id,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
/* End access to the dataset and release resources used by it. */
status = H5Dclose(dataset_id);
/* Terminate access to the data space. */
status = H5Sclose(dataspace_id);
/* Close the file. */
status = H5Fclose(file_id);
}
I am not getting any compile time error, but run time error saying it is not able load some lib. The error is pasted below -
19:36:27 macOS_ ⚡ h5cc -show myprog.c
clang -arch x86_64 myprog.c -L/Users/Ajay/anaconda/lib -lhdf5_hl -lhdf5 -arch x86_64 -lpthread -lz -ldl -lm
19:36:33 macOS_ ⚡ ./a.out
dyld: Library not loaded: #rpath/libhdf5_hl.10.dylib
Referenced from: /Users/Ajay/opensource/HDF5-Examples/./a.out
Reason: image not found
Abort trap: 6
19:36:35 macOS_ ⚡
more information on configuration -
09:11:59 macOS_ ⚡ h5cc -showconfig
SUMMARY OF THE HDF5 CONFIGURATION
=================================
General Information:
-------------------
HDF5 Version: 1.8.17
Configured on: Tue Aug 2 08:44:51 BST 2016
Configured by: ray#rays-Mac.local
Configure mode: production
Host system: i386-apple-darwin11.4.2
Uname information: Darwin rays-Mac.local 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 16:25:48 PDT 2012; root:xnu-1699.32.7~1/RELEASE_X86_64 x86_64
Byte sex: little-endian
Libraries: shared
Installation point: /Users/Ajay/anaconda
Compiling Options:
------------------
Compilation Mode: production
C Compiler: /usr/bin/clang ( Apple LLVM version 4.2 )
CFLAGS: -arch x86_64
H5_CFLAGS: -O3
AM_CFLAGS:
CPPFLAGS:
H5_CPPFLAGS: -DNDEBUG -UH5_DEBUG_API
AM_CPPFLAGS:
Shared C Library: yes
Static C Library: no
Statically Linked Executables: no
LDFLAGS: -arch x86_64
H5_LDFLAGS:
AM_LDFLAGS:
Extra libraries: -lpthread -lz -ldl -lm
Archiver: ar
Ranlib: ranlib
Debugged Packages:
API Tracing: no
Languages:
----------
Fortran: no
C++: yes
C++ Compiler: /usr/bin/clang++ ( Apple LLVM version 4.2 )
C++ Flags: -arch x86_64
H5 C++ Flags: -O3
AM C++ Flags:
Shared C++ Library: yes
Static C++ Library: no
Features:
---------
Parallel HDF5: no
High Level library: yes
Threadsafety: yes
Default API Mapping: v18
With Deprecated Public Symbols: yes
I/O filters (external): deflate(zlib)
MPE: no
Direct VFD: no
dmalloc: no
Clear file buffers before write: yes
Using memory checker: no
Function Stack Tracing: no
Strict File Format Checks: no
Optimization Instrumentation: no
lib locations
09:11:56 macOS_ ⚡ ls /Users/Ajay/anaconda/lib | grep hdf5
-rwxr-xr-x 2 Ajay staff 17232 Aug 2 2016 libhdf5_hl_cpp.11.dylib
-rwxr-xr-x 2 Ajay staff 123256 Aug 2 2016 libhdf5_hl.10.dylib
-rwxr-xr-x 2 Ajay staff 445776 Aug 2 2016 libhdf5_cpp.12.dylib
-rwxr-xr-x 2 Ajay staff 2622428 Aug 2 2016 libhdf5.10.dylib
lrwxr-xr-x 1 Ajay staff 20 Mar 25 09:11 libhdf5_cpp.dylib -> libhdf5_cpp.12.dylib
lrwxr-xr-x 1 Ajay staff 16 Mar 25 09:11 libhdf5.dylib -> libhdf5.10.dylib
-rwxr-xr-x 1 Ajay staff 1087 Mar 25 09:11 libhdf5_hl_cpp.la
lrwxr-xr-x 1 Ajay staff 23 Mar 25 09:11 libhdf5_hl_cpp.dylib -> libhdf5_hl_cpp.11.dylib
-rwxr-xr-x 1 Ajay staff 988 Mar 25 09:11 libhdf5_hl.la
lrwxr-xr-x 1 Ajay staff 19 Mar 25 09:11 libhdf5_hl.dylib -> libhdf5_hl.10.dylib
-rwxr-xr-x 1 Ajay staff 993 Mar 25 09:11 libhdf5_cpp.la
-rw-r--r-- 1 Ajay staff 2243 Mar 25 09:11 libhdf5.settings
-rwxr-xr-x 1 Ajay staff 937 Mar 25 09:11 libhdf5.la
Based on the comment I can now run using
DYLD_LIBRARY_PATH=/Users/Ajay/anaconda/lib ./a.out
How to make it permanent ?
I am not on a Mac and don't use Anaconda. I'll try to guess-diagnose your problem anyway :-)
The program builds but will not execute. There is a mismatch between the libraries that are requested by the executable (libhdf5_hl.10.dylib) and the ones that are in your system.
You are using Anaconda installed hdf5. You must check what is the compiler used by Anaconda to build hdf5 and use the same.
The easiest way out is if all that is missing is the DYLD_LIBRARY_PATH path to /Users/Ajay/anaconda/lib. Try
DYLD_LIBRARY_PATH=/Users/Ajay/anaconda/lib ./a.out
For further info, please provide the output of
ls /Users/Ajay/anaconda/lib | grep hdf5
h5cc -showconfig

GCC linking libc static and some other library dynamically, revisited?

The following questions are relevant but do not answer my question:
Linking partially static and partially dynamic in GCC
Linking a dynamic library to a static library that links to other static libraries
GCC: static linking only some libraries
Static link of shared library function in gcc
I asked a very similar question earlier, but since the previous question started by me got somewhat cluttered in the comment section and not fully answered (but I flagged it as answered since it was a good effort and did at least partially answer it) I will ask a new question. The question is specifically how to link libc as static, while linking some other library (e.g. libm) dynamically. This was suggested that cannot be done in the first question, is that true? If so it would be very interesting to know why not.
Is it even possible to do this? Someone made a comment (which was removed for some reason, maybe it was incorrect?) that it is possible, but there must then also exist a dynamically linked version of libc, since it will be required by the dynamic library (e.g. dynamic libm will require dynamic libc (?)).
This is fine for me, but it is not obvious to me how to tell GCC to do this, i.e. link in libc as both static and dynamic. How do I do this (I made a couple attempts, some are shown later in the question)? Or is there some other way to do what I want?
We first see that by simply running gcc test.c -lm, everything is linked in dynamically, as follows:
$ gcc test.c -lm
$ ldd a.out
linux-vdso.so.1 (0x00007fffb37d1000)
libm.so.6 => /lib64/libm.so.6 (0x00007f3b0eeb6000)
libc.so.6 => /lib64/libc.so.6 (0x00007f3b0eb10000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3b0f1b0000)
To link only libm as static, while allowing libc to remain dynamic, we can do (as Z boson pointed out in one of the aforementioned questions):
$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libm.a
$ ldd a.out
linux-vdso.so.1 (0x00007fff747ff000)
libc.so.6 => /lib64/libc.so.6 (0x00007f09aaa0c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f09aadb2000)
However, attempting the same procedure to link libc static and libm dynamic, does not seem to work:
$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a -lm
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
What does this error message mean?
Some other attempts (most were also included in my first question):
$ gcc test.c /usr/lib64/libc.a
linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
urned 1 exit status
$ gcc test.c -Wl,-Bdynamic -lm -Wl,-Bstatic -lc
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bdynamic -lm -Wl,-Bstatic -lc test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bstatic -lc -Wl,-Bdynamic -lm test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.so -lm
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.so /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a -lm
Note that the last one compiled/linked successfully. However libc has not been linked in statically, only dynamically, so it is another failed attempt.
The test program is simply the following:
$ cat test.c
#include <stdio.h>
#include <math.h>
int main(int argc, char **argv)
{
int i;
int result;
for(i = 0; i < 65535; i++) {
result = sin(i);
}
return 0;
}
Edit:
I've also tried statifier and ermine, as suggested in this question:
Static link of shared library function in gcc
Neither works.
Basically, your first approach is the correct way to do this:
gcc test.c libc.a -lm
After gcc adds the implicit libraries it'll look (conceptually) like this:
gcc crt1.o test.c libc.a -lm -lc -lgcc -lc
So that means that any libc functions called by either crt1.o or test.c will be pulled in from libc.a and linked statically, whereas any functions called solely from libm or libgcc will be linked dynamically (but it will reuse the static functions if libm calls something already pulled in).
The linker always starts at the left-most file/library, and works rightwards; it never goes back. .c and .o files are linked in unconditionally, but .a files and -l options are only used to find functions that are already referenced but not yet defined. Therefore, a library at the left is pointless (and -lc must appear twice because -lc depends on -lgcc, and -lgcc depends on -lc). Link order is important!
Unfortunately, you appear to have been foiled by what might be a bug in strcmp (or rather in the libc that contains strcmp): the STT_GNU_IFUNC thing is a clever feature that allows multiple versions of a function to be included, and the most optimal one to be selected at runtime, based on what hardware is available. I'm not sure, but it looks like this feature is only available in a PIE (Position Independent Executable) or shared library build.
Why that would be in a static libc.a is a mystery to me, but there's an easy workaround: implement your own strcmp (a basic, slow implementation is only a few lines of C), and link it in before libc.a.
gcc test.c mystrcmp.c libc.a -lm
Alternatively, you can extract the functions from libc.a that you really want, and link only those in statically:
ar x libc.a
gcc test.c somefile.o -lm
ar is to .a files, as tar is to .tar files, although the command usage varies a bit, so this example extracts the .o files from the .a file, and then links them explicitly.
Based on the answer by ams I did the follow
mystrcmp.c
int strcmp(const char *s1, const char *s2) {
}
Compile
gcc -c test.c
gcc -c mystrcmp.c
Setup files
ln -s `gcc -print-file-name=crt1.o`
ln -s `gcc -print-file-name=crti.o`
ln -s `gcc -print-file-name=crtn.o`
ln -s `gcc -print-file-name=libgcc_eh.a`
ln -s `gcc -print-file-name=libc.a`
ln -s `gcc -print-file-name=libm.so`
Link
ld -m elf_x86_64 -o math crt1.o crti.o test.o mystrcmp.o libc.a libgcc_eh.a libc.a libm.so -dynamic-linker /lib64/ld-linux-x86-64.so.2 crtn.o
This links and runs correctly. However, ldd shows
linux-vdso.so.1 => (0x00007fff51911000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8182470000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f81820a9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8182793000)
It appears that dynamic libm requires dynamic libc. Actually, that's easy to show
ldd libm.so reports
linux-vdso.so.1 => (0x00007fff20dfe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcaf74fe000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaf7bed000)
So it's impossible to link to libm.so without linking libc.so as well unless you manage to compile libm without the dependency on libc.
just use
gcc sample_uart.c -static -static-libgcc -static-libstdc++
# lddtree a.out
a.out => ./a.out (interpreter => none)
#################### test ############################
ar x /usr/lib/arm-linux-gnueabihf/libc.a
-rw-r--r-- 1 root root 792 Oct 28 00:38 wmemset.o
-rw-r--r-- 1 root root 2456 Oct 28 00:38 wmemstream.o
-rw-r--r-- 1 root root 1616 Oct 28 00:38 wordcopy.o
-rw-r--r-- 1 root root 18544 Oct 28 00:38 wordexp.o
-rw-r--r-- 1 root root 1384 Oct 28 00:38 wprintf_chk.o
-rw-r--r-- 1 root root 1088 Oct 28 00:38 wprintf.o
-rw-r--r-- 1 root root 884 Oct 28 00:38 write_nocancel.o
-rw-r--r-- 1 root root 1368 Oct 28 00:38 write.o
-rw-r--r-- 1 root root 1340 Oct 28 00:38 writev.o
-rw-r--r-- 1 root root 1084 Oct 28 00:38 wscanf.o
-rw-r--r-- 1 root root 3924 Oct 28 00:38 wstrops.o
-rw-r--r-- 1 root root 2112 Oct 28 00:38 xcrypt.o
-rw-r--r-- 1 root root 1504 Oct 28 00:38 xdr_array.o
-rw-r--r-- 1 root root 836 Oct 28 00:38 xdr_float.o
-rw-r--r-- 1 root root 2344 Oct 28 00:38 xdr_intXX_t.o
-rw-r--r-- 1 root root 1740 Oct 28 00:38 xdr_mem.o
-rw-r--r-- 1 root root 4696 Oct 28 00:38 xdr.o
-rw-r--r-- 1 root root 3880 Oct 28 00:38 xdr_rec.o
-rw-r--r-- 1 root root 1640 Oct 28 00:38 xdr_ref.o
-rw-r--r-- 1 root root 1556 Oct 28 00:38 xdr_sizeof.o
-rw-r--r-- 1 root root 2464 Oct 28 00:38 xdr_stdio.o
-rw-r--r-- 1 root root 1688 Oct 28 00:38 xlocale.o
-rw-r--r-- 1 root root 936 Oct 28 00:38 xmknodat.o
-rw-r--r-- 1 root root 944 Oct 28 00:38 xmknod.o
-rw-r--r-- 1 root root 1052 Oct 28 00:38 xpg_basename.o
-rw-r--r-- 1 root root 1640 Oct 28 00:38 xpg-strerror.o
-rw-r--r-- 1 root root 900 Oct 28 00:38 xstat64.o
-rw-r--r-- 1 root root 1184 Oct 28 00:38 xstatconv.o
-rw-r--r-- 1 root root 1196 Oct 28 00:38 xstat.o
root#hi3798mv100:~/sample/uart#
root#hi3798mv100:~/sample/uart#
root#hi3798mv100:~/sample/uart# gcc sample_uart.c -lm
root#hi3798mv100:~/sample/uart# gcc sample_uart.c *.o -lm
/usr/bin/ld: dso_handle.o:(.data.rel.ro.local+0x0): multiple definition of `__dso_handle'; /usr/lib/gcc/arm-linux-gnueabihf/9/crtbeginS.o:(.data.rel.local+0x0): first defined here
/usr/bin/ld: rcmd.o: in function `__validuser2_sa':
(.text+0x418): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
collect2: error: ld returned 1 exit status

How can I use a GMP library I just built from source?

I've got a tiny C program with the following header:
#include <gmp.h>
I compile it doing:
gcc test.c -o test.o -L/gmp_install/lib -lgmp
And then I can run it fine. But it is using the "stock" GMP library on my system.
Now I'd like to compile it using another version of the GMP lib, which I installed locally and I can't make it work.
The new library is apparently installed in /usr/local/lib:
... $ ls -l /usr/local/lib
-rw-r--r-- 1 root staff 1276320 Jun 15 02:22 libgmp.a
-rwxr-xr-x 1 root staff 914 Jun 15 02:22 libgmp.la
lrwxrwxrwx 1 root staff 16 Jun 15 02:22 libgmp.so -> libgmp.so.10.2.0
lrwxrwxrwx 1 root staff 16 Jun 15 02:22 libgmp.so.10 -> libgmp.so.10.2.0
-rwxr-xr-x 1 root staff 528715 Jun 15 02:22 libgmp.so.10.2.0
But no matter what I try, it's apparently the old library that is used.
Even using:
gcc perf.c -o perf.o -O3 -L/ -lgmp
But it's using the GMP version in /usr/lib/x86_64-linux-gnu/.
What is the correct way to use the GMP version in /usr/local/bin, knowing I'd like to keep the old version too?
Also, once the executable is created, is there an easy way to see which library it shall use at runtime? (can I create the executable with one version of GMP and then execute it with another version of GMP, knowing the lib is dynamically linked?)
Do two things:
Use -L/usr/local/lib flag while compiling
Set LD_LIBRARY_PATH variable while running your program to have /usr/local/lib. Thus, if you are using a bash shell, you will have to do something like
$ export LD_LIBRARY_PATH=/usr/local/lib
$ ./your_program
to use the /usr/local/lib version at runtime. Also, in order to see which one it will use at runtime, you can always do ldd <your binary name> which will print out all the dynamic dependencies.

Resources