scons linking problems depending on CC - linker

I'm compiling a library that comes with a scons script. According to the documentation scons does everything automatically and stuff should just work.
However, the build succeeds or fails, depending on what I set CC to (even though I always invoke the same compiler):
/usr/bin/ld: context.os: relocation R_X86_64_32S against `a local symbol' can not be used when making a shared object; recompile with -fPIC
context.os was built with the following arguments.
env cc -o context.os -c ... -Wall -O2 -DNDEBUG -I. -I/usr/local/include ... context.c
So scons forgets the -fPIC argument. However if I set CC=cc it succeeds:
cc -o context.os -c ... -Wall -O2 -fPIC -DNDEBUG ...
The same if I set CC="ccache cc":
ccache cc -o context.os -c ... -Wall -O2 -fPIC -DNDEBUG ...
And of course, with -fPIC set, linking succeeds in both cases.
So, I wonder how does scons position independent code trigger work and why does it screw up in the CC="env cc" case?

Related

Makefile: how to specify library name at the end of command using patsubst

I am new to Makefile, C and Linux. I am using gcc & ubuntu. I encountered a problem while trying to compile the code with a link to a library.
Here is my problem. I have:
a_tests.c & b_tests.c files in "tests" folder
lib.a file in "build" folder
Here is the codes in Makefile related to the problem:
CFLAGS=-g -O2 -Wall -Wextra -Isrc -DNDEBUG $(OPTFLAGS)
TARGET=build/lib.a
TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(patsubst %.c,%,$(TEST_SRC))
tests: CFLAGS += $(TARGET)
tests: $(TESTS)
When the tests files are compiled, "undefined reference to 'XXXfunction'"errors will be prompted. Because what executed behind is
gcc -g -O2 -Wall -Wextra -Isrc -DNDEBUG build/lib.a tests/a_tests.c -o test/a_tests
gcc -g -O2 -Wall -Wextra -Isrc -DNDEBUG build/lib.a tests/b_tests.c -o test/b_tests
But "build/lib.a" should be placed after the output file name to solve it (If I manually type in the below commands, the codes would be successfully compiled), ie:
gcc -g -O2 -Wall -Wextra -Isrc -DNDEBUG tests/a_tests.c -o test/a_tests build/lib.a
gcc -g -O2 -Wall -Wextra -Isrc -DNDEBUG tests/b_tests.c -o test/b_tests build/lib.a
But I don't know how to change in the Makefile, I tried -l -L options, they didn't work. It would warn that "cannot find the .a file". Any help would be appreciated. Thank you so much in advance!
Define the library as a dependency, because it is one. It will be appended at the end of the other dependencies, here: the source.
CFLAGS=-g -O2 -Wall -Wextra -Isrc -DNDEBUG $(OPTFLAGS)
TARGET=build/lib.a
TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(TEST_SRC:%.c=%)
tests: $(TESTS)
$(TESTS): $(TARGET)
The library does not need to be after the output file, but after the depending input file.
The makefile is further simplified:
Replaced the patsubst with a simpler expression.
Moved the target tests up, so it is found as the first and therefore default target.
Good luck!

gcc flags equivalent to LD_PRELOAD?

I currently compile a program called do_foo like so:
gcc -Wall -Wextra -g3 -pthread do_foo.c -o do_foo
and I run it like this:
LD_LIBRARY_PATH=.. LD_PRELOAD=libfoo.so ./do_foo
libfoo.so is strange because:
Has a bunch of functions marked with __attribute__((constructor)) and
Intercepts libc functions like malloc, send, etc
Instead of using LD_PRELOAD to link libfoo.so, I'd like to do it at compile time. I would expect to be able to do it like this:
gcc -Wall -Wextra -g3 -L.. -lfoo -pthread do_foo.c -o do_foo_ld
but this doesn't work: none of the ctor functions run and none of the libc functions get intercepted. When I run ldd do_foo_ld, I don't see libfoo.so in the list of libraries linked to it.
What gcc flags are equivalent to LD_PRELOAD? I assume t here is some simple translation between the two, but I haven't been able to find it.
EDIT: I've made some progress with the following:
gcc -Wall -Wextra -g3 -nodefaultlibs -pthread -L.. -lfoo -lc -lgcc do_foo.c -o do_foo_ld
My rationale is that I need to prevent loading libc at first with -nodefaultlibs, then link libfoo.so, then manually pull whatever gets taken out by nodefaultlibs in afterwards. With this, I don't get undefined reference errors about symbols from libc, but I do get the following:
/tmp/ccSsQHmx.o: In function `fun_1':
/my/proj/do_foo.c:217: undefined reference to `pthread_create'
/tmp/ccSsQHmx.o: In function `fun_2':
/my/proj/do_foo.c:269: undefined reference to `pthread_create'
/tmp/ccSsQHmx.o: In function `fun_3':
/my/proj/do_foo.c:281: undefined reference to `pthread_join'
No combination of -pthread -lpthread at various points in the gcc invocation seems to fix it, and I'm not sure why. I thought that nodefaultlibs might mean "prevent any of the default libraries from being linked" rather than just "don't link them yet," so I tried making a new symlink:
ln -s /lib/x86_64-linux-gnu/libpthread.so.0 ../libnotpthread.so
and adding the following:
gcc -Wall -Wextra -g3 -nodefaultlibs -pthread -L.. -lfoo -lnotpthread -lc -lgcc do_foo.c -o do_foo_ld
but no dice.
What am I missing here?
You should put linked libraries after source or object files:
gcc -Wall -Wextra -g3 do_foo.c -L.. -lfoo -pthread -o do_foo_ld
If this fails to work, try the big hammer:
gcc -Wall -Wextra -g3 do_foo.c -Wl,--no-as-needed -L.. -lfoo -Wl,--as-needed -pthread -o do_foo_ld
Modern distroes enable -Wl,--as-needed flag by default which forces -lfoo to be ignored if none of preceding source or object files uses it (in your case there are no files so it's considered to be unused).

How to compile with a .o file that was compiled with other .o files (C99)

consider c.c a code that includes a.h and b.h, and main.c a code that includes c.h
i tried to compile it like so
gcc --std=c99 -o a.o -c a.c
gcc --std=c99 -o b.o -c b.c
gcc --std=c99 -o c.o -c c.c a.o b.o
but when I run the last one, gcc yells at me
gcc --std=c99 -o c.o -c c.c a.o b.o
gcc: warning: a.o: linker input file unused because linking not done
gcc: warning: b.o: linker input file unused because linking not done
and then when I try to compile the main.c file using gcc -o main main.c c.o it says that there are a lot of undefined references, which is predictable once the c file was not correctly compiled.
I've seen some similar questions here at stackoverflow, but I couldn't get it to work neither way.
I'm on Arch Linux running gcc v4.9.2-3
First, it is -std=c99 with a single dash.
I guess you are on Linux.
Then, you always should pass -Wall -Wextra -g (especially since you are a newbie) to gcc : -Wall ask for nearly all warnings, -Wextra for even more warnings, -g ask for debug information.
At last, you want to produce an executable myprog (don't name executables as c.o, this is supposed to be an object file) with
gcc -std=c99 -Wall -Wextra -g -o myprog c.c a.o b.o
You need to remove any -c since you want the linking to happen.
If you really mean -but that is very unusual today, better make shared libraries!- to agglomerate several object files into one all.o (to be linked later with other objects) you might try the -r linker option
gcc -std=c99 -Wall -Wextra -g -r c.c a.o b.o -o all.o
But last time I tried it was in the previous century, so details could be wrong.
There are very few reasons to agglomerate objects using the -r linker option. Unless you really know what you are doing, you are very probably wrong (in trying -r).
Perhaps you want to make a software library. These days it is much better to make a shared library. A shared library (technically an ELF shared object) should contain position independent code. So, assuming you have three translation units t1.c, t2.c, t3.c you first compile them as PIC :
gcc -std=c99 -Wall -Wextra -g -fPIC t1.c -c -o t1.pic.o
gcc -std=c99 -Wall -Wextra -g -fPIC t2.c -c -o t2.pic.o
gcc -std=c99 -Wall -Wextra -g -fPIC t3.c -c -o t3.pic.o
then you link all these PIC object files into a shared library libmyt.so
gcc -std=c99 -Wall -Wextra -g -shared \
t1.pic.o t2.pic.o t3.pic.o \
-o libmyt.so
Later you'll use this shared library e.g. as
gcc -std=c99 -Wall -Wextra -g main.o -o myprog -Wl,-rpath . libmyt.so
or as
gcc -std=c99 -Wall -Wextra -g main.o -o myprog -Wl,-rpath . -L. -lmyt
You might consider static linking with ar to make a static library libmyt.a but I don't recommend that.
Of course, you'll debug your program using gdb ./myprog and you could try running it with ./myprog. To use valgrind, try valgrind ./myprog
If you have several translation units, better learn how to use GNU make. Read the Program Library HowTo and this and these hints.

using C and cuda create shared library got error at link stage

I was really struggled with this error when I try to build a shared library. My code utilize the Lapacke library and also CUDA. when I compile them, there are no errors(I compile them as)
gcc -m64 -Wall -fPIC -c xxx.c -o xxx.o $(INC)
where INC includes all directories
INC=-I. -I${JAVA_HOME}/include/ -I${JAVA_HOME}/include/linux/ I$/home/sniu/lapack-3.5.0/lapacke/include/ -I${CUDA_INSTALL_PATH}/include/ -I/home/sniu/CBLAS/include/
for cuda part, I wrote it as:
nvcc -m64 -arch=sm_20 -Xcompiler -fPIC $(INC) -c xxx.cu -o xxx.o
but I got the error message at the link stage:
gcc -m64 -D_REENTRANT -Wall -fPIC -g -shared -o libjniWrapper.so jniWrapper.o cholesky_inv.o wls_acc.o utils.o -L/home/sniu/lapack-3.5.0 -L/opt/cuda-toolkit/5.5.22/lib64 -lm -llapacke -llapack -lblas -lgfortran -lrt -lcudart -lcublas -ldl
/usr/bin/ld: /home/sniu/lapack-3.5.0/liblapacke.a(lapacke_dpotrf.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
/home/sniu/lapack-3.5.0/liblapacke.a: could not read symbols: Bad value
collect2: error: ld returned 1 exit status
I am very sure libraries are there, I really confused why I got this error.
Any suggestions are appreciated, Thank you so much!

linking pthread library issue

Am facing a problem that may be slightly complicated to explain and understand as giving the entire picture would be too big and difficult.
Please excuse me for it.
Consider the following Makefile:
all: clients.so simulator backup
LD_PRELOAD=/home/Juggler/client/clients.so ./simulator
backup: backup.c libclient.a
gcc backup.c -o backup -L /home/Juggler/client -L. -lclient -ldl
simulator: simulator.c libclient.a
gcc -g simulator.c -o simulator -L /home/Juggler/client -L. -lclient -ldl -pthread
libclient.a: libclient.o client.o
ar rcs libclient.a libclient.o client.o
libclient.o:libclient.c
gcc -c libclient.c -o libclient.o -pthread
clients.so: client.o client_invoke.o
ld -shared -o clients.so client_invoke.o client.o -ldl
client_invoke.o: client_invoke.c
gcc -Wall -fPIC -DPIC -c -g client_invoke.c
client.o: client.c
gcc -Wall -fPIC -DPIC -c -g client.c -ldl -pthread
We call function written in client.c from libclient.c and these functions in client.c make call to pthread_key_create(), pthread_setspecific..etc.
Threads are created by simulator.c and theses threads access functions written in he other files.
On doing make...Errors like the following appear.
/home/Juggler/client/libclient.a(client.o):In function 'setup_connection':
/home/Juggler/client/client.c:35: undefined reference to 'pthread_setspecific'
pthread.h has been included in both client.c and libclient.c
Would be grateful for anypointers . I understand information is very less...
Thanks
On linux, pthread functions live in the libpthread library. So you have to link to that.
The proper way, when using pthreads, is to compile and link using the -pthread , which, among other things, will link in the pthread library. You have the -pthread flag for some of your executables, but not for others, and not for your clients.so library, so add the flag where required.
Also, remember, when you are creating a shared library, you should compile the source files with the -fPIC flag.
(And, seems you are calling ld directly to produce the client.so library, you really should use gcc to do the linking.)

Resources