I want to find the libc.so file that's being used in a Rust build so that I can query it with --version. (Some libcs expose their version information via C macros, so an alternative for them would be to use the cc crate in a build script. But others like musl don't.)
I can figure out which libstd-*.so file a rust binary or library will be linked against. When this libstd.so is linked against the host's libc, then running ldd on it shows that libc.so. But when the host system is using glibc and the targeted environment is musl, this doesn't work ("Invalid ELF header"). Instead of ldd, I could instead use readelf -d or objdump -p on the libstd.so. But these only show the filename of the libc.so file it uses, not its full path. And that libc.so isn't at any of the directories in LD_LIBRARY_PATH. (I do know where it is on my own systems, but I'm trying to find it programmatically on arbitrary systems.)
Running ldconfig -p only gives me information about the libc for the host system.
It would be great if there were a rustc equivalent of gcc's and clang's -print-file-name=libc.so, so that I could do something like rustc --target=$TARGET --print-file-name=libc.so.
Other ideas about how I could get this information?
You can pass linker arguments to rustc like so:
rustc -C link-args=...
To find out which libc.so is used, I believe the following command should suffice:
rustc -C link-args=-Wl,-t ...
From man ld:
-t
--trace
Print the names of the input files as ld processes them. ...
Update:
This didn't work: rustc "eats up" the output from the linker.
I was able to get the desired output indirectly:
echo 'fn main() { println!("")}' | rustc -C link-args=-Wl,-Map=map.out -o foo -
grep 'libc\.so' map.out
libc.so.6 /usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-f25e49a311b0f577.rlib(std-f25e49a311b0f577.std.cy8lhng1-cgu.2.rcgu.o) (setuid##GLIBC_2.2.5)
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libc.so
LOAD /lib/x86_64-linux-gnu/libc.so.6
Related
On Arch-Linux when linking an object file with ld to a dynamically linked ELF executable, it uses /lib/ld64.so.1 as the default dynamic linker. However, my dynamic linker is /lib/ld-2.26.so from Glibc.
I know, that I can specify the dynamic linker to ld with the --dynamic-linker option, but how can I ensure, that when compiling for other Linux distributions, the correct dynamic linker is found. In other words: how can I find the correct name of the dynamic linker on Linux?
Link with gcc -nostartfiles or gcc -nostdlib instead of using ld directly.
(With -no-pie or -pie if you want to make that choice explicit).
The system gcc knows the right path for the ELF interpreter.
Or to find out what the right path is, file /bin/ls and parse the output. On my Arch Linux system, it includes ... dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
Other programs include readelf -p /bin/ls, and ldd /bin/ls also includes the right path.
(But note that ldd includes the right path even if you use it on an ELF executable that has the wrong path; /bin/ldd is a shell script that works by running the ELF interpreter on an executable with special args, so the shell script contains paths to try, and the runtime dynamic linker doesn't look for itself because it's already running. You can use file or readelf -a to inspect executables to check for the right path, but not ldd.)
For example, I've got a 'b.c' file, I compile and generate the code, while I wish to see an intermediate assembly file, I can do under shell like this:
gcc -S b.c
gcc -c b.c
gcc b.o -o b
My question is, how to specify inside scons SConstruct, with all these steps, to make sure I get b.s, b.o and 'b' executable? Seems scons only support functions like Program, Object, Library, so I only get b.o and 'b'. But how to make out 'b.s', while I don't wish to introduce any duplicated work by the compiler(to save time).
Thanks.
I have the usual gcc on my machine (at /usr/bin/gcc), and another one (newer) is linked when I setup the environment for a certain framework which I'm working on.
And I would like to compile with the old one I have on /usr/bin/gcc, instead of using the newer one.
I have to use "gmake" command for the compilation (custom compilation setup).
Without changing the PATH, how could I "tell" gmake to use a different gcc?
from command line:
gmake CC=/usr/bin/gcc
Use
make CC=/opt/bin/my-gcc
And make sure that for compilation you use $(CC) instead of direct gcc:
foo.o: foo.c
$(CC) -c foo.c -o foo.o
If you use default compilation patters the gmake uses CC variable by default
In your makefile, define a variable for your preferred compiler.
CC=/usr/bin/gcc
And after your target, use the variable.
a.o : a.c
$(CC) ...
How does one find out what is the lib that the above flag is referring to?
How would I do it for some other one?
The -l option takes the name of the library as the argument so in this case the library would be named libXi.a (or libXi.so or something similar). To find the library look in the standard library locations (/usr/lib, /lib, /usr/local/lib, etc.) available in your distribution. There may also be additional library directories specified using the -L option to the linker.
If your program compiled successfully, or if you have another program which uses -lXi, then you can do:
ldd /path/to/that/program | grep libXi
For example:
$ ldd /usr/X11R6/bin/audacity | grep libXi
libXinerama.so.1 => /usr/lib/libXinerama.so.1 (0x00007f53faaba000)
libXi.so.6 => /usr/lib/libXi.so.6 (0x00007f53f8e2c000)
And that will most likely tell you where that library is. (It's not 100% because the build process could alter the search path but that's usually not likely for standard libraries like X11.)
From there, you can ask your distro which package has that file, if you care. For example on Ubuntu or a .deb-base distro:
$ dpkg --search /usr/lib/libXi.so.6
libxi6: /usr/lib/libXi.so.6
If you can't use LDD, then check your system's /etc/ld.so.conf which will indicate the search path for runtime shared library linking. (/lib/ and /usr/lib are included by default.)
Worst case, you could just find for it:
find / -regex '.*libXi\.\(a\|so\).*' 2> /dev/null
strace -f -e open gcc ... -lXi
Look for libXi in the output.
What is the usage of the -I and -L flags in a makefile?
These are typically part of the linker command line, and are either supplied directly in a target action, or more commonly assigned to a make variable that will be expanded to form link command. In that case:
-L is the path to the directories containing the libraries. A search path for libraries.
-l is the name of the library you want to link to.
For instance, if you want to link to the library ~/libs/libabc.a you'd add:
-L$(HOME)/libs -labc
To take advantage of the default implicit rule for linking, add these flags to the variable LDFLAGS, as in
LDFLAGS+=-L$(HOME)/libs -labc
It's a good habit to separate LDFLAGS and LIBS, for example
# LDFLAGS contains flags passed to the compiler for use during linking
LDFLAGS = -Wl,--hash-style=both
# LIBS contains libraries to link with
LIBS = -L$(HOME)/libs -labc
program: a.o b.o c.o
$(CC) $(LDFLAGS) $^ $(LIBS) -o $#
# or if you really want to call ld directly,
# $(LD) $(LDFLAGS:-Wl,%=%) $^ $(LIBS) -o $#
Even if it may work otherwise, the -l... directives are supposed to go after the objects that reference those symbols. Some optimizations (-Wl,--as-needed is the most obvious) will fail if linking is done in the wrong order.
To really grok a makefile, you need to also have a good understanding of the command lines for all of the components of your project's toolchain. Options like -I and -L are not understood by make itself. Rather, make is attempting to create a command line that will execute a tool to transform a prerequisite file into a target file.
Often, that is a C or C++ source file being compiled to an object file, and eventually linked to get an executable file.
In that case, you need to see the manual for your compiler, and especially the bits related to the command line options it understands.
All that said in generic terms, those specific options are pretty standard among compilers and linkers. -I adds a directory to the list of places searched by the compiler for a file named on a #include line, and -L adds a directory to the list of places searched by the linker for a library named with the -l option.
The bottom line is that the "language" of a makefile is a combination of the syntax of the makefile itself, your shell as known to make (usually /bin/sh or something similar), common shell commands (such as rm, cp, install, etc.), and the commands specific to your compiler and linker (e.g. typing gcc -v --help at your shell prompt will give you a nearly complete (and extremely long) list of the options understood by gcc as one starting point).
One thing to note is that these are the options passed to the compiler/linker.
So you should be looking at the compiler man pages/documentation to know their role.