gcc has -M-class options (-MMD, -MF, etc.) that allows to generate dependency file during compiling source file. The dependency file contains Makefile rules describing on which source files and headers the generated object file depends on. The dependency file may be included into Makefile and then make will automatically recompile source file when headers are changed.
I need a similar option but for generating dependency file during linking an executable. The dependency file should contain list of libraries used for linking an executable, so if any of libraries is updated, make will re-execute linking of the executable automatically.
I tried to use the same flags (-MMD, -MF), but they doesn't work for linking. It seems they are only for generating dependency files during compiling.
Is there any other flags or means for generating dependency file for executable?
So far I have not found dedicated gcc options for generating dependency file for executable, but found the --trace option (-Wl,--trace when used with gcc). This option generates list of libraries used during linking. Its output has the next format:
gcc -Wl,--trace myprog.c -o myprog -L. -lmylib
-lmylib (./libmylib.a)
-lgcc_s (/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/libgcc_s.so)
...
The list of libraries then may be converted to Makefile rules using sed:
echo "myprog: " > myprog.dep
gcc -Wl,--trace myprog.c -o myprog -L. -lmylib \
| sed -n 's/.*(\(.*\)).*/\1 \\/p' >> myprog.dep
So myprog.dep will have the following content:
myprog: \
./libmylib.a \
/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/libgcc_s.so \
...
This dependency file may be included to Makefile and make will relink myprog if any of libraries are updated.
The dependency file doesn't contain list of object files, but the object files are usually known inside Makefile-script without help of compiler:
myprog: $(OBJS)
gcc -Wl,--trace $^ -o myprog -L. -lmylib | sed -n 's/.*(\(.*\)).*/\1 \\/p' >> myprog.dep
Related
I am trying to create a shared library that is to be linked against OpenSSL-1.0.2p which depends on libssl1.0. The installed version of OpenSSL on my ubuntu bionic machine is however OpenSSL-1.1.1 which internally uses libssl1.1.
Since I do not wish to install OpenSSL-1.0 system-wide, I downloaded and compiled it separately installing it into a folder inside my home directory.
I wish to use this location against which I would want my shared library to link. Here is the Makefile for the shared library that I am trying to create:
APPBASE=/home/AB/Documents/APP/APP_2.17.0
OPENSSL1.0.2p_INSTALL_LOC=/home/AB/Documents/APP/OpenSSL-1.0.2p-installation
CC=gcc
#CFLAGS= -Wall -g -O -fPIC
CFLAGS= -Wall -g -O -static
RM= rm -f
.PHONY: all clean
src=$(wildcard *Generic/*.c *Linux/*.c)
$(info source=$(src))
#we use the custom compiled openssl version
#and NOT the one available on the system
#INC=-I/usr/include/openssl
INC+=-I$(OPENSSL1.0.2p_INSTALL_LOC)/include/openssl
INC+=$(foreach d,$(incdir),-I$d)
$(info includes=$(INC))
LIB=-L$(OPENSSL1.0.2p_INSTALL_LOC)/lib
LIB+=-l:libssl.a -l:libcrypto.a
# looks like we need this for proper static linking of libc
LIB+= -static-libgcc
$(info links=$(LIB))
obj=$(src:.c=.o)
#all: libAPP.so
all: libAPP.a
clean:
$(RM) *.o *.so
$(shell find $(APPBASE) -type f -iname "*.o" -exec rm -rf {} \;)
.c.o:
${CC} ${CFLAGS} $(INC) -c $< -o $#
#${CC} ${CFLAGS} $(INC) -c $< -o $#
libAPP.a: $(obj)
#ar rcs $# $^
#$(LINK.c) -shared $^ -o $#
However, make reports that the header files being included are from the system's openssl installation and hence the compile is failing (since it is expecting OpenSSL-1.0.2p). Here's a sample:
In file included from /usr/include/openssl/e_os2.h:13:0,
from /usr/include/openssl/bio.h:13,
from /usr/include/openssl/x509v3.h:13,
.... (source file 1)
gcc -static -Wall -g -O -fPIC -I/home/AB/Documents/APP/OpenSSL-1.0.2p-installation/include/openssl -I*/path/to/app/include1* -I*/path/to/app/include2* -c */path/to/src1* -L/home/AB/Documents/APP/OpenSSL-1.0.2p-installation/lib -lssl -lcrypto
sr1.c: In function ‘Get_CACertificates’: warning: implicit declaration of function ‘CRYPTO_w_lock’; did you mean ‘CRYPTO_zalloc’? [-Wimplicit-function-declaration]
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
^~~~~~~~~~~~~
CRYPTO_zalloc
CRYPTO_w_lock is a macro which is no longer present in the latest version of crypto.h (OpenSSL-1.1) which makes it clear that my application is still looking at the system version of OpenSSL.
Within my source files, I am including the SSL header files like so:
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
Although angular braces are supposed to tell the compiler to look into the system's header files, doesn't the -L on the command line as well as the -I flags force it to look for them in the said directories before looking at the system files?
I do have a crypto.h file in the custom install location for OpenSSL but the compiler seems to be ignore it for some reason
ab#ab1-pc:/home/AB/Documents/APP/OpenSSL-1.0.2p-installation$ find . -iname "crypto.h"
./include/openssl/crypto.h
What am I missing here?
UPDATE 1: As suggested by Darren, removed the trailing openssl so now my include path is
INC+=-I$(OPENSSL1.0.2p_INSTALL_LOC)/include and voila I can see the shared library getting created. However when I try to find references to ssl within this newly minted shared library, I see that I have 87 entries (which includes ALL symbols having ssl as part of their name)
ab#ab1-pc:~/Documents/AB/APP_2.17.0$ nm libAPP.so | grep -i "ssl" | wc -l
87
whereas listing only the global symbols from libssl.a tells me it has 1113 globally defined symbols.
ab#ab1-pc:~/Documents/AB/APP_2.17.0$ nm -g ../OpenSSL-1.0.2p-installation/lib/libssl.a | grep -i "ssl" | wc -l
1113
Shouldn't the former count be MORE than the latter?? Has it got something to do with the fact that my 'app' is a shared library? Even then shouldn't it pull in ALL the symbols (at least the global ones) from any static libraries it links against??
UPDATE 2: Now apparently since I was facing issues with SSL symbols, I switched to creating a static library so made changes to the makefile accordingly.
In this line:
INC+=-I$(OPENSSL1.0.2p_INSTALL_LOC)/include/openssl
... try changing it to:
INC+=-I$(OPENSSL1.0.2p_INSTALL_LOC)/include
... i.e., without the 'openssl' part.
Your includes, e.g.,
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
... expect directory search paths to terminate on the 'include/', not on the 'openssl'.
how to see what .o files constitute .so file?
Means how to notice what are the object files are used to build the .so file from the .so file (If I have only the .so file)
You can't know, given just a shared library, what object files were
compiled into it. If you're lucky, you may be able to make a reasonable guess.
A shared library is made, by the linker, from object files and
possibly other shared libraries, but it does not contain the object files
or shared libraries from which it was made. A static library, on the other hand, which
is made by the archiver ar, does contain object
files: it is just an ar archive of object files.
If a shared library has not been stripped of debugging information, then
for debugging purposes its symbol table will contain the names of the source files
from which the object files were compiled that were linked in the shared library - at least those source files which were compiled with debugging information.
From the names of those source files you can infer the names of the object files
with reasonable confidence, but not with certainty.
For example, here we make a shared library from source files foo.c and bar.c.
Compile the source files to object files:
$ gcc -Wall -fPIC -c -o foo.o foo.c
$ gcc -Wall -fPIC -c -o bar.o bar.c
Link the object files to make a shared library:
$ gcc -shared -o libfoobar.so foo.o bar.o
Then:
$ readelf -s libfoobar.so | grep FILE
26: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
35: 0000000000000000 0 FILE LOCAL DEFAULT ABS foo.c
37: 0000000000000000 0 FILE LOCAL DEFAULT ABS bar.c
39: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
42: 0000000000000000 0 FILE LOCAL DEFAULT ABS
indicates that three source files have contributed debugging info to the
library, and we'd infer that the object files to which they were compiled
were likely to be:
crtstuff.o
foo.o
bar.o
Note that crtstuff.c is not one of the source files that we compiled. It
happens to contain program initialization and finalization code from the C runtime library, which has got into
our library from a C runtime object file that is linked by default.
This inference could be wrong about any of the files, since:
$ gcc -Wall -fPIC -c -o abc.o foo.c
$ gcc -Wall -fPIC -c -o xyz.o bar.c
$ gcc -shared -o libfoobar.so abc.o xyz.o
is also a perfectly possible way of compiling and linking the library.
If debugging information has been stripped from the library:
$ strip -g libfoobar.so
then we are out of luck:
$ readelf -s libfoobar.so | grep FILE
$
No more FILE symbols.
I installed OCaml via OPAM, and by default it uses gcc as the command to compile .c files. For instance, if I run ocamlopt -verbose file.c, I obtain:
+ gcc -Wall -D_FILE_OFFSET_BITS=64 -D_REENTRANT -g
-fno-omit-frame-pointer -c -I'/home/user/.opam/4.02.1+fp/lib/ocaml' 'test.c'
I'd like to change the GCC binary that is used by OCaml, for instance to replace it with gcc-5.1 or /opt/my-gcc/bin/gcc.
Is it possible to do so without reconfiguring and recompiling OCaml? I suppose I could add a gcc alias to a directory in the PATH, but I'd prefer a cleaner solution if there is one.
To check if gcc was not chosen based on a textual configuration file (that I could easily change), I searched for occurrences of gcc in my /home/user/.opam/4.02.1+fp directory, but the only occurrence in a non-binary file that I found was in lib/ocaml/Makefile.config, and changing it does nothing for the already-compiled binary.
ocamlopt uses gcc for three things. First, for compiling .c files that appear on the command line of ocamlopt. Second, for assembling the .s files that it generates internally when compiling an OCaml source file. Third, for linking the object files together at the end.
For the first and third, you can supply a different compiler with the -cc flag.
For the second, you need to rebuild the OCaml compiler.
Update
Here's what I see on OS X when compiling a C and an OCaml module with the -verbose flag:
$ ocamlopt -verbose -cc gcc -o m m.ml c.c 2>&1 | grep -v warning
+ clang -arch x86_64 -c -o 'm.o' \
'/var/folders/w4/1tgxn_s936b148fdgb8l9xv80000gn/T/camlasm461f1b.s' \
+ gcc -c -I'/usr/local/lib/ocaml' 'c.c'
+ clang -arch x86_64 -c -o \
'/var/folders/w4/1tgxn_s936b148fdgb8l9xv80000gn/T/camlstartup695941.o' \
'/var/folders/w4/1tgxn_s936b148fdgb8l9xv80000gn/T/camlstartupb6b001.s'
+ gcc -o 'm' '-L/usr/local/lib/ocaml' \
'/var/folders/w4/1tgxn_s936b148fdgb8l9xv80000gn/T/camlstartup695941.o' \
'/usr/local/lib/ocaml/std_exit.o' 'm.o' \
'/usr/local/lib/ocaml/stdlib.a' 'c.o' \
'/usr/local/lib/ocaml/libasmrun.a'
So, the compiler given by the -cc option is used to do the compilation of the .c file and the final linking. To change the handling of the .s files you need to rebuild the compiler. I'm going to update my answer above.
I am trying to compile Pro*C lib on Linux.I have following code in my make.
etc=$TABS_HOME/admin
export etc
if [ -f ${1}.pc ]
then
rm $1_x.o
compc $1
make -f $etc/proc64.mk $1_x.o
ar -cvq libtabs.a $1_x.o
else
make -f $etc/proc64.mk $1.o
ar -cvq libtabs.a $1.o
fi
Here is the final command that printed when compilation started:
/usr/bin/gcc -g -m64 -g -I/export/home/cl10gr2/oracle/rdbms/public -I/home/med/src/common -I/u01/app/oradb11r2/product/11.2.0/dbhome_3/rdbms/demo -
I/u01/app/oradb11r2/product/11.2.0/dbhome_3/rdbms/public -
I/u01/app/oradb11r2/product/11.2.0/dbhome_3/precomp/public -ltabs.a -lnapi.a -c commonutil_x.c
I am getting following warning/Error:
gcc: -ltabs.a: linker input file unused because linking not done
gcc: -lnapi.a: linker input file unused because linking not done
Can any please help me out why it is not linking the lib files?
Its not linking them because you aren't linking. You are passing the -c option:
-c Compile or assemble the source files, but do not link. The linking stage simply is not done. The ultimate output is in the form of an object file for each source file.
If you are building intermediate object files, you don't need the libraries until the very end. Include all of the object files and libraries you need in the final stage and link them all together.
I was trying to do something like this in a makefile:
program.exe: ui.o main.o
gcc ......etc
ui.o: window1.o window2.o
gcc -c window1.o window2.o -o ui.o #this doesn't want to work
window1.o: window1.c window1.h window1_events.c window1_controls.c ...
gcc -c window1.c window1_events.c window1_controls.c... -o window1.o
window2.o: ...
gcc ...
main.o: ...
gcc ...
but when I compile like this, it gives the error "input file unused because linking not done," and then I get a bunch of unresolved externs, etc--problems which are resolved by changing
program.exe: ui.o main.o
gcc ...
to
program.exe: window1.o window2.o main.o
gcc ...
so is it possible to just link object files together, to avoid having mile-long lines in a makefile and break down the build process a little more?
Yes: to merge several object files into one, use ld -r or ld -Ur:
From "man ld" on Linux:
-r
--relocatable
Generate relocatable output---i.e., generate an output file that can
in turn serve as input to ld. This is often called partial linking.
As a side effect, in environments that support standard Unix magic
numbers, this option also sets the output file’s magic number to
"OMAGIC".
If this option is not specified, an absolute file is produced.
When linking C++ programs, this option will not resolve references to
constructors; to do that, use -Ur.
You could also do this with gcc:
gcc -Wl,-r foo.o bar.o -o foobar.o -nostdlib
Merging object files like this has some advantages over using an archive library: if merged files change very infrequently (compared to say main.c), your final executable links will be faster.
OTOH, with archived library, the linker will only use what it needs, so your executable may end up being smaller if e.g. window2.c ends up not being necessary.
I bunch of object files is a library. You can create a library with the ar
utility. The following example creates a library called mylib.a containing the files foo.o and bar.o
ar rvs mylib.a foo.o bar.o
You can then link with it by using it on the compiler command line:
gcc -o myexe main.c mylib.a
To create a library:
ar rvs somelib.a file1.o file2.o file3.o
To link it:
gcc -o program.exe file4.o somelib.a