How to use static library with gcc under linux - linux

I'm trying to use a static library 'mylib.a' created with 'ar'. The examples I have seen use -L and -l to name the library. My attempts at using these fail. However, if I simply put the library file name on the linker command it works. (I'm overlooking something obvious?) Using gcc 4.8.4 Ubuntu 14.04 (see comment in code.) The f?.c and mymain.c are trivially simple. Thanks!
#!/bin/bash
# cc -v shows...
# gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.1)
cc -c -Wall -Wstrict-prototypes -o fa.o fa.c
cc -c -Wall -Wstrict-prototypes -o fb.o fb.c
cc -c -Wall -Wstrict-prototypes -o fc.o fc.c
cc -c -Wall -Wstrict-prototypes -o mymain.o mymain.c
ar -rcs mylib.a fa.o fb.o fc.o
# THIS WORKS
#cc -o mypgm mymain.o mylib.a
# THESE FAIL WITH ERROR '/usr/bin/ld: cannot find -lmylib'
cc -o mypgm mymain.o -L. -lmylib
# OR
cc -o mypgm mymain.o -static -L. -lmylib
###

As noted in a comment…
When you use -lname, the linker looks for libname.a or libname.so in one of the directories that it has (already) been told to search for libraries.
You can either rename your library to libmine.a and then -L. -lmine will work, or rename it to libmylib.a and then -lmylib will work (but the repeated lib looks a bit clumsy, or neophytic).

Related

How does make use variables when expanding and compiling before linking?

Info:
Linux watvde0453 3.10.0-1062.1.1.el7.x86_64 #1 SMP Fri Sep 13 22:55:44 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
GNU Make 4.2.1
Built for x86_64-pc-linux-gnu
Hi
I have been playing around with a make file to allow builds of shared, static libraries and an exe (and also to get some sort of understanding about how it works) and came across some behavior I do not understand.
I was trying to separate out the flags used for lib / exe into separate variables, but when using a line to compile and link all in one it looks like only the CFLAGS variable is being included for the compile step.
When using the following makefile:
LIBCFLAGS := -fPIC
CFLAGS := -O3 -g -Wall -Werror
CC := gcc
SRCS=hashfunction.c hashtable.c hashtablelinkedlist.c
OBJS=hashfunction.o hashtable.o hashtablelinkedlist.o
LIBSO = lib$(NAME).so
libso: $(OBJS)
$(CC) $(LIBCFLAGS) $(CFLAGS) -shared -o $(LIBSO) $(OBJS)
I get the following output when running the make command for libso:
$ make libso
gcc -O3 -g -Wall -Werror -c -o hashfunction.o hashfunction.c
gcc -O3 -g -Wall -Werror -c -o hashtable.o hashtable.c
gcc -O3 -g -Wall -Werror -c -o hashtablelinkedlist.o hashtablelinkedlist.c
gcc -fPIC -O3 -g -Wall -Werror -shared -o lib.so hashfunction.o hashtable.o hashtablelinkedlist.o
/tools/oss/packages/x86_64-centos7/binutils/default/bin/ld: hashtable.o: relocation R_X86_64_32 against `.rodata.str1.8' can not be used when making a shared object; recompile with -fPIC
hashtable.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
make: *** [Makefile:12: libso] Error 1
I can get it all working by sticking all the flags in CFLAGS, but I was wondering if anyone could explain what make is doing underneath ?
It looks like the $(LIBCFLAGS) is being ignored for the implicit compile lines, but $(CFLAGS) is not. Is CFALGS used implicitly by make for all compilations ?
You can see all the built-in rules make knows about by running make -p -f/dev/null. There you'll see:
%.o: %.c
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
which is the built-in rule make uses to create a .o file from a .c file. Looking elsewhere in the output you'll see:
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
so these are the variables make uses to compile .c files into .o files.

Swap unix compiler flags with a shorter one

I've been running ns3 sumulations in linux and every time I compiled I had to type
g++ -Wall -o simulacija simulacija.cc -DNS3_ASSERT_ENABLE -DNS3_LOG_ENABLE `pkg-config --libs --cflags
libns3.16-core-debug libns3.16-network-debug libns3.16-applications-debug libns3.16-internet-debug
libns3.16-point-to-point-debug libns3.16-point-to-point-layout-debug libns3.16-csma-debug
libns3.16-csma-layout-debug libns3.16-topology-read-debug libns3.16-wifi-debug`
Is there a way to shorten the flags to eg:
g++ -Wall simulacija.cc -o simulacija -my_params
Thank you
The GCC compiler supports the # notation to embed a sequence of arguments inside a file. Read near end of GCC overall options page.
So you could put in some file params.args the following lines
-Wall
-I /usr/local
-DNS3_ASSERT_ENABLE
-DNS3_LOG_ENABLE
-O
and just invoke
g++ #params.args simulacija.cc -o simulacija
You could have a Makefile rule to build that params.args (e.g. with pkg-config etc...)
Actually, it is time to learn how to use GNU make.
Notice that the # option is not understood by some other compilers like GCC handles it.
You can create a shell script myparams.sh that outputs your parameters:
#!/bin/sh
echo -n "-DNS3_ASSERT_ENABLE -DNS3_LOG_ENABLE"
pkg-config --libs --cflags libns3.16-core-debug [...]
Now you can run
g++ -Wall simulacija.cc -o simulacija `./myparams.sh`
(Don't forget to chmod +x myparams.sh)

My lib_LTLIBRARIES library links, but check_LTLIBRARIES one does not?

I have a new c++ project built with autoconf, automake and libtool. Functionality is divided up into support libraries and user binaries. There is also a set of unittests binaries which link against these libraries, are built and run at make check time, but are not installed.
I said the the project is new. I'm actually just now getting around to extracting the first library that should be installed. Until now the (small amount of) written code was just compiled directly into a unittests.
My attempted Makefile.am snippet looks like this:
lib_LTLIBRARIES += libfoo.la
libfoo_la_SOURCES = foo.cc
In make check, I get this:
/bin/bash ./libtool --tag=CXX --mode=link g++ -Wall -Wextra -Werror -ansi -fprofile-arcs -ftest-coverage -g -O0 -fprofile-arcs -ftest-coverage -L/usr/local/lib -Wl,-rpath /usr/local/lib -o libfoo.la -rpath /usr/local/lib foo.lo -lboost_thread-mt -lboost_system-mt -pthread
libtool: link: g++ -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6.1/crtbeginS.o .libs/foo.o -L/usr/local/lib -lboost_thread-mt -lboost_system-mt -L/usr/lib/gcc/x86_64-linux-gnu/4.6.1 -L/usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../.. -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/4.6.1/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../../x86_64-linux-gnu/crtn.o -fprofile-arcs -O0 -fprofile-arcs -Wl,-rpath -pthread -pthread -Wl,-soname -Wl,libfoo.so.0 -o .libs/libfoo.so.0.0.0
/usr/bin/ld: cannot find libfoo.so.0: No such file or directory
collect2: ld returned 1 exit status
Notice the missing library is precisely the one I'm trying to compile.
(The library is not libfoo, but I am able to reproduce the same error with this stub library. The Makefile.am and error lines above are literal and unedited.)
If I change the automake lines to
check_LTLIBRARIES += libfoo.la
libfoo_la_SOURCES = foo.cc
then the compile looks like this:
/bin/bash ./libtool --tag=CXX --mode=link g++ -Wall -Wextra -Werror -ansi -fprofile-arcs -ftest-coverage -g -O0 -fprofile-arcs -ftest-coverage -L/usr/local/lib -Wl,-rpath /usr/local/lib -o libfoo.la foo.lo -lboost_thread-mt -lboost_system-mt -pthread
libtool: link: ar cru .libs/libfoo.a .libs/foo.o
libtool: link: ranlib .libs/libfoo.a
libtool: link: ( cd ".libs" && rm -f "libfoo.la" && cp -p "../libfoo.la" "libfoo.la" )
..and everything works fine (except my library isn't installed, being in check_.)
Notice the only difference in the command lines is some additional arguments in the 2nd one:
... -Wl,-rpath /usr/local/lib -o libfoo.la -rpath /usr/local/lib foo.lo -lboost_thread-mt ...
I don't know offhand if this new argument shouldn't be there, but it does appear to be causing the problem. Does anyone know what I'm missing?
Some more details:
On osx lion, this works fine (and the command lines are different.) This error manifests on
ubuntu 12.04, possibly other linuxes.
noinst_LTLIBRARIES and EXTRA_LTLIBRARIES work like check_LTLIBRARIES: no extra arguments, and it links. It seems libtool 'convenience' libraries are specifically the ones without these arguments.
automake 1.11.1
autoconf 2.68
libtool 2.4
EDIT
(Manually) dropping -Wl,-rpath /usr/local/lib from the arguments also fixes the problem.
I did it to myself. While bringing in autoconf support for boost, I encountered a bug described here. My work-around followed the suggestion of one post:
diff --git a/m4/boost.m4 b/m4/boost.m4
index 3d4e47c..9dd0c43 100644
--- a/m4/boost.m4
+++ b/m4/boost.m4
## -403,7 +403,7 ## dnl generated only once above (before we start the for loops).
LDFLAGS=$boost_save_LDFLAGS
LIBS=$boost_save_LIBS
if test x"$Boost_lib" = xyes; then
- Boost_lib_LDFLAGS="-L$boost_ldpath -Wl,-R$boost_ldpath"
+ Boost_lib_LDFLAGS="-L$boost_ldpath -Wl,-rpath $boost_ldpath"
Boost_lib_LDPATH="$boost_ldpath"
break 6
else
The -rpath introduced here is the same one apparently causing the issue. If I revert this change, the problem goes away (I am of course left with the first issue, but that's another story.)

arguments file to gcc

On Linux, is there a way to pass arguments to gcc from a file. That is to gave file like compile.args
% cat compile.args
-g3
-ggdb
-pedantic
-pedantic-errors
-Wall
-Werror
-O0
vec1.cpp
-o vec1
and then give this file to g++/gcc. I can do this using cat compile.args | xargs g++, is they any other way? Does gcc support this?
thanks.
Yes, just run gcc #compile.args
For verbosity, also something like this should work (depending on running shell)
g++ `cat compiler.args|xargs`
or
COMPILE_ARGS=`cat compiler.args|xargs` g++ ${COMPILE_ARGS}

Linking OpenSSL libraries to a program

I have built OpenSSL from source (an intentionally old version; built with ./config && make && make test) and would prefer to use what I have built without doing make install to link against my program.
The command that's failing is:
gcc -Wall -Wextra -Werror -static -Lopenssl/openssl-0.9.8k/ -lssl -lcrypto
-Iopenssl/openssl-0.9.8k/include -o myApp source1.o source2.o common.o`
And I receive a series of errors similar to:
common.c:(.text+0x1ea): undefined reference to `SSL_write'
This makes me think there's something funky with my OpenSSL. If I omit -Lopenssl/openssl-0.9.8k/ from my command, the error changes to being unable to:
/usr/bin/ld: cannot find -lssl
/usr/bin/ld: cannot find -lcrypto
Am I compiling OpenSSL incorrectly? Or how should I best resolve this?
Silly "Linux-isms" strike again! Apparently, I need to change my command such that the -L and -l stuff is at the end like (despite what man gcc seems to indicate):
gcc -Wall -Wextra -Werror -static -o myApp source1.o source2.o common.o -Lopenssl/openssl-0.9.8k/ -lssl -lcrypto -Iopenssl/openssl-0.9.8k/include
Why don't you want to use make install? It can copy generated binaries in the directory you want if you previously passed it to ./configure --prefix $HOME/target_library_install_directory
If you used this trick with every library you build and install, you could then add the target directory to the LIBRARY_PATH environment variable and avoid using -L option.
If you use Autotools, or you are building an Autools project like cURL, then you should be able to use pkg-config. The idea is the Autotools package will read OpenSSL's package configuration and things will "just work" for you.
The OpenSSL package configuration library name is openssl.
You would use it like so in a makefile based project.
%.o: %.c
$(CC) -o $# -c `pkg-config --cflags openssl` $^
target: foo.o bar.o baz.o
$(CC) -o $# `pkg-config --libs openssl` $^
Also see How to use pkg-config in Make and How to use pkg-config to link a library statically.
Another approach is to use pkg-config to preserve compatibility. This is an example of makefile when needs to link OpenSSL.
CC = gcc
CFLAGS = \
-I. \
-D_GNU_SOURCE=1
LDFLAGS = `pkg-config --libs inih`
LDFLAGS += `pkg-config --libs libcurl`
LDFLAGS += `pkg-config --libs liburiparser`
LDFLAGS += `pkg-config --libs openssl`
# Executable
foo: foo.o
$(CC) -o $# $^ $(LDFLAGS)
foo.o: foo.c
$(CC) -c $(CFLAGS) $< -o $#

Resources