Link a C .o file before a shared .so in Rust - rust

My Rust main function depends on a C object file foo.o, which depends on a C shared library libbar.so.
I need to link foo.o before libbar.so in Rust,
I tried rust-link-lib=foo. It only works for libraries that begin with lib and end with .so or .a.
I tried rust-link-arg=foo.o and rust-link-lib=bar. It puts foo.o after -lbar, which results in an undefined reference error.
Compile the C .o and .so files,
gcc -c foo.c
gcc -fPIC -shared -o libbar.so bar.c
Linking in gcc succeeds,
gcc main.c -o main foo.o -L./ -lbar
LD_LIBRARY_PATH=./ ./main
Linking in rust
cargo run
failed with
= note: /usr/bin/ld: foo.o: in function `foo':
foo.c:(.text+0x10): undefined reference to `bar'
collect2: error: ld returned 1 exit status
Sample code here.
Thank you for your help.

Related

why one error show,when i use the linker ld to link the assembly files generated by rust

1,I used the following instructions to generate the LLVM IR
rustc --emit=llvm-ir main.rs
2,then convert to assembly code using LLC
llc-10 main.ll -o main.s
3,want to compile main.s into an executable
Using assembler -- as
as -o main.o main.s
Using linker -- ld
ld -s -o main main.o
while one error appeared, which is “undefined reference to rust_eh_personality”.
enter image description here
i want to ask why and how can i do?

Exclude dynamic dependencies from build command?

Let's suppose we have a library libutils.so:
ldd libutils.so
...
libdependency.so
...
Let's further suppose that we need to build an application:
g++ appliation.cpp -lutils -o application
May we omit -ldependency in the above command or must we write:
g++ appliation.cpp -lutils -ldependency -o application
May we omit -ldependency in the above command
If you control the linkage of libutils.so itself, yes you can. An illustration:
main.c
extern void foo(void);
int main(void)
{
foo();
return 0;
}
foo.c
extern void bar(void);
void foo(void)
{
bar();
}
bar.c
#include <stdio.h>
void bar(void)
{
puts(__func__);
}
We'll make a program that depends on libfoo.so, which depends on libbar.so.
Make the object files:
$ gcc -Wall -c -fPIC foo.c bar.c
gcc -Wall -c main.c
Now link libbar.so the No Frills way:
$ gcc -shared -o libbar.so bar.o
Next link libfoo.so like this:
$ gcc -shared -o libfoo.so foo.o -L. -lbar -Wl,-rpath=$(pwd)
The effect of the -rpath linker option is:
-rpath=dir
Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects.
All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime.
The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link;
see the description of the -rpath-link option. If -rpath is not used when linking an ELF executable,
the contents of the environment variable LD_RUN_PATH will be used if it is defined.
The result is that:
$ objdump -x -j .dynamic libfoo.so | egrep '(RUNPATH|NEEDED)'
NEEDED libbar.so
RUNPATH /home/imk/develop/so/scrap
libfoo.so has a NEEDED entry inscribed in its .dynamic section saying that
the library has a runtime dependency on libbar.so. Likewise it has
a RUNPATH entry there saying that runtime dependencies may be searched for in /home/imk/develop/so/scrap
That's just the pwd where I did the linkage: it doesn't have to be that, as long as is indeed
a directory where libbar.so can be found when the linker or loader comes looking for it.
This information can be read by the linker, when libbar.so is linked with something else,
and by the loader at runtime. So finally I can link prog like this:
$ gcc -o prog main.o -L. -lfoo -Wl,-rpath=$(pwd)
I don't need to mention -lbar, because libfoo.so itself provides the linker with
the information that libfoo.so depends on libbar.so, and where to look for it.
Since I also passed -rpath=$(pwd) in the linkage of prog, we see that prog
will provide this information
$ objdump -x -j .dynamic prog | egrep '(RUNPATH|NEEDED)'
NEEDED libfoo.so
NEEDED libc.so.6
RUNPATH /home/imk/develop/so/scrap
to the runtime loader: prog needs libfoo.so, and it can be looked for
in /home/imk/develop/so/scrap. When the loader finds libfoo.so and loads it, it will
discover from it that:
NEEDED libbar.so
RUNPATH /home/imk/develop/so/scrap
and will in turn find and load libbar.so, which will enable it to resolve all
symbols referred to in the process under construction. Consequently, prog can be run immediately:
$ ./prog
bar
I didn't have to pass -rpath=$(pwd) in the linkage of prog. But if I hadn't:
$ gcc -o prog main.o -L. -lfoo
$ ./prog
./prog: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
the loader wouldn't know where to find libfoo.so. See:
$ ldd prog
linux-vdso.so.1 (0x00007ffffcc35000)
libfoo.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4d1aff9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4d1b5ec000)
And then I'd have to resort to:
$ export LD_LIBRARY_PATH=.
$ ldd prog
linux-vdso.so.1 (0x00007fff964dc000)
libfoo.so => ./libfoo.so (0x00007fc2a7f35000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc2a7b44000)
libbar.so => ./libbar.so (0x00007fc2a7942000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc2a8339000)
$ ./prog
bar
Later
it is still a little bit unclear whether the presence of libdependency.so among the output of ldd libutils.so is enough to omit -ldependencny during linkage
You would need to ask at least one and at most two questions about the output of ldd utils.so:-
Does the ldd libutils.so output report the so-name libdependency.so at all?
If Yes to 1, does it also resolve that so-name to an actual file?
If No to 1 then libdutils.so contains no informatation about its dependency of libdependency.so
and you must specify -lutils -ldependency in any further linkage.
If Yes to 1 but No to 2 (i.e.ldd libutils.so reports libdependency.so => not found) then libutils.so has
a NEEDED entry for the so-name libdependency.so but not a RUNPATH entry by which the linker or
loader can resolve that so-name to any actual file. In that case again, you must link -lutils -ldependency if you link -lutils, so that the linker will then search for a file that resolves -ldependency. At least, you must do so as long as ldd libutils.so still reports libdependency.so => not found when you do the linkage. Read on...
If Yes to 1 and Yes to 2 then you can drop -ldependency in a further linkage provided it is
run in the same environment in which you ran ldd libutils.so
That caveat is needed because if ldd libutils.so resolves libdependency.so, all you know
is that ldd was able to resolve libdependency.so using the loader's search algorithm:-
The LD_LIBRARY_PATH environment variable (in the active shell), lists a directory
in which libdependency.so is found, or
libutils.so provides a RUNPATH in which libdependency.so is found, or
libdependency.so is found in one of the directories listed in /etc/ld.so.conf (or the recursive include-expansion thereof), or
libdependency.so is found in one of the loader's trusted search directories, /lib and /usr/lib
If ldd can resolve libdependency.so in one of those four ways, then the linker will be able
to do it the same way, as long as that way still succeeds when you do the linkage.
So going back to my example, and my linkage:
$ gcc -shared -o libfoo.so foo.o -L. -lbar -Wl,-rpath=$(pwd)
After that, thanks to -rpath=$(pwd). I can link prog like:
$ gcc -o prog main.o -L. -lfoo
without mentioning -lbar, and it succeeds. Now I link libfoo.so instead without
an -rpath:
$ gcc -shared -o libfoo.so foo.o -L. -lbar
after which:
$ objdump -x -j .dynamic libfoo.so | egrep '(RUNPATH|NEEDED)'
NEEDED libbar.so
there's no RUNPATH anymore, and consequently:
$ ldd libfoo.so
linux-vdso.so.1 (0x00007ffda05e6000)
libbar.so => not found
because the loader can't resolve libbar.so in any other way either.
Now I can no longer link prog without -lbar:
$ gcc -o prog main.o -L. -lfoo
/usr/bin/ld: warning: libbar.so, needed by ./libfoo.so, not found (try using -rpath or -rpath-link)
./libfoo.so: undefined reference to `bar'
But if I do:
$ export LD_LIBRARY_PATH=$(pwd)
then:
$ ldd libfoo.so
linux-vdso.so.1 (0x00007ffe56d1e000)
libbar.so => /home/imk/develop/so/scrap/libbar.so (0x00007fd2456e8000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd2452f7000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd245aec000)
libfoo.so's dependency libbar.so is resolved by the loader, using the LD_LIBRARY_PATH, and in the
same way by the linker:
$ gcc -o prog main.o -L. -lfoo; echo Done
Done
And if I clear LD_LIBRARY_PATH again:
$ unset LD_LIBRARY_PATH
$ gcc -o prog main.o -L. -lfoo; echo Done
/usr/bin/ld: warning: libbar.so, needed by ./libfoo.so, not found (try using -rpath or -rpath-link)
./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
Done
back to failure.

Cliclock CC Build Error 'undefined reference' [duplicate]

I'm trying to compile my project and I use the lib ncurse. And I've got some errors when compiler links files.
Here is my flags line in Makefile:
-W -Wall -Werror -Wextra -lncurses
I've included ncurses.h
Some layouts :
prompt$> dpkg -S curses.h
libslang2-dev:amd64: /usr/include/slcurses.h
libncurses5-dev: /usr/include/ncurses.h
libncurses5-dev: /usr/include/curses.h
prompt$> dpkg -L libncurses5-dev | grep .so
/usr/lib/x86_64-linux-gnu/libncurses.so
/usr/lib/x86_64-linux-gnu/libcurses.so
/usr/lib/x86_64-linux-gnu/libmenu.so
/usr/lib/x86_64-linux-gnu/libform.so
/usr/lib/x86_64-linux-gnu/libpanel.s
And here are my erros :
gcc -W -Wall -Werror -Wextra -I./Includes/. -lncurses -o Sources/NCurses/ncurses_init.o -c Sources/NCurses/ncurses_init.c
./Sources/NCurses/ncurses_init.o: In function `ncruses_destroy':
ncurses_init.c:(.text+0x5): undefined reference to `endwin'
./Sources/NCurses/ncurses_init.o: In function `ncurses_write_line':
ncurses_init.c:(.text+0xc5): undefined reference to `mvwprintw'
./Sources/NCurses/ncurses_init.o: In function `ncurses_init':
ncurses_init.c:(.text+0xee): undefined reference to `initscr'
collect2: error: ld returned 1 exit status
Thanks a lot
You need to change your makefile so that the -lncurses directive comes after your object code on the gcc command line, i.e. it needs to generate the command:
gcc -W -Wall -Werror -Wextra -I./Includes/. -o Sources/NCurses/ncurses_init.o -c Sources/NCurses/ncurses_init.c -lncurses
This is because object files and libraries are linked in order in a single pass.
In C++ , I fixed it just by linking the ncurses library .
Here is the command :
g++ main.cpp -lncurses
I got flags to correct order by using LDLIBS variable:
ifndef PKG_CONFIG
PKG_CONFIG=pkg-config
endif
CFLAGS+=-std=c99 -pedantic -Wall
LDLIBS=$(shell $(PKG_CONFIG) --libs ncurses)
man gcc | grep -A10 "\-l library"
-l library
Search the library named library when linking. (The second alternative with the library as a separate argument is only for POSIX
compliance and is not recommended.)
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files
in the order they are specified. Thus, foo.o -lz bar.o searches
library z after file foo.o but
before bar.o. If bar.o refers to functions in z, those functions may not be loaded.

Library linkage in makefile using gfortran

I have a fortran code (pardiso_1.f) and it needs some libraries (BLAS, lapack and Pardiso libraries) to be compiled. When I try to compile it, I link libraries before compilation and I write this line in linux terminal:
gfortran pardiso_1.f -L/home/behnam/Pardiso -lpardiso412-GNU450-X86-64 -L/usr/lib -lblas -llapack -fopenmp
and it works perfectly.
However I have to run the code using makefile. I am so new in writing makefiles and I do not know how to do the linkage. I have written this makefile. could anyone help me to find out what is wrong with that?
FC = gfortran
OPT = -O2
PROGRAMS = pardiso_1
all: $(PROGRAMS)
FFLAGS = -fopenmp
#### BLAS, LAPACK and PTHREAD libraries
LBLAS = /usr/lib/
###location of pardiso file
LIBMKL = /home/behnam/PS2/
#### Series of libraries
LIBRARIES= -llapack -lblas -lpthread -lm -lpardiso412-GNU430-X86-64
PATHFC = /usr/bin/
nlace: ${PATHFC}${FC} ${OPT} ${FFLAGS} -I${PROGRAMS} -o nlace.exe \
-L${LIBMKL} -lpardiso412-GNU430-X86-64\
-L${LBLAS} ${LIBRARIES}
clean:
rm -f *.o *.exe fort.* *~ *.mod
veryclean: clean
rm -f *~ $(PROGRAMS)
The errors are:
behnam#meen-392430:~/testing$ make
make: Warning: File `Makefile' has modification time 23 s in the future
gfortran -fopenmp pardiso_1.f -o pardiso_1
/tmp/ccYNexaH.o: In function `MAIN__':
pardiso_1.f:(.text+0xb3): undefined reference to `pardisoinit_'
pardiso_1.f:(.text+0x2ae): undefined reference to `pardiso_chkmatrix_'
pardiso_1.f:(.text+0x36e): undefined reference to `pardiso_chkvec_'
pardiso_1.f:(.text+0x44c): undefined reference to `pardiso_printstats_'
pardiso_1.f:(.text+0x5ae): undefined reference to `pardiso_'
pardiso_1.f:(.text+0x860): undefined reference to `pardiso_'
pardiso_1.f:(.text+0xb78): undefined reference to `pardiso_'
pardiso_1.f:(.text+0xe00): undefined reference to `pardiso_'
collect2: ld returned 1 exit status
make: *** [pardiso_1] Error 1
Your makefile does not contain the -L/home/behnam/Pardiso part of your command line.
Your rule for PROGRAMS does not contain a recipe that includes the library calls. I presume you want something like your nlace rule, but right now, make is not calling any of your -L switches as part of its operation.

How to include all objects of an archive in a shared object?

When compiling our project, we create several archives (static libraries), say liby.a and libz.a that each contains an object file defining a function y_function() and z_function(). Then, these archives are joined in a shared object, say libyz.so, that is one of our main distributable target.
g++ -fPIC -c -o y.o y.cpp
ar cr liby.a y.o
g++ -fPIC -c -o z.o z.cpp
ar cr libz.a z.o
g++ -shared -L. -ly -lz -o libyz.so
When using this shared object into the example program, say x.c, the link fails because of an undefined references to functions y_function() and z_function().
g++ x.o -L. -lyz -o xyz
It works however when I link the final executable directly with the archives (static libraries).
g++ x.o -L. -ly -lz -o xyz
My guess is that the object files contained in the archives are not linked into the shared library because they are not used in it. How to force inclusion?
Edit:
Inclusion can be forced using --whole-archive ld option. But if results in compilation errors:
g++ -shared '-Wl,--whole-archive' -L. -ly -lz -o libyz.so
/usr/lib/libc_nonshared.a(elf-init.oS): In function `__libc_csu_init':
(.text+0x1d): undefined reference to `__init_array_end'
/usr/bin/ld: /usr/lib/libc_nonshared.a(elf-init.oS): relocation R_X86_64_PC32 against undefined hidden symbol `__init_array_end' can not be used when making a shared object
/usr/bin/ld: final link failed: Bad value
Any idea where this comes from?
You could try (ld(2)):
--whole-archive
For each archive mentioned on the command line after the --whole-archive option, include every object file in the
archive in the link, rather than searching the archive for the required object files. This is normally used to turn
an archive file into a shared library, forcing every object to be included in the resulting shared library. This
option may be used more than once.
(gcc -Wl,--whole-archive)
Plus, you should put -Wl,--no-whole-archive at the end of the library list. (as said by Dmitry Yudakov in the comment below)

Resources