How can I use --whole-archive with libtool without it being reordered?
Background:
I'm compiling Extrae (performance profiling) from sources which depends on Dyninst which depends on libdwarf, which, on Debian Wheezy, is provided as a static library (usr/lib/libdwarf.a).
Dyninst is compiled from sources:
# ./configure --with-libdwarf-static; make; make install
creates:
/usr/lib/libdynDwarf.so.8.1
/usr/lib/libdyninstAPI.so.8
Then Extrae is compiled from sources.
# ./configure --with-mpi=/usr --with-mpi-libs=/usr/lib --with-papi=/usr/local --with-unwind=/usr --with-dyninst=/usr --with-dwarf=/usr --with-dwarf-libs=/usr/lib
...
# make
...
/bin/sh ../../../libtool --tag=CXX --mode=link g++ -I../../../src/common -I/usr/include -g -O2 -Wall -W -L/usr/lib64 -ldyninstAPI -L/usr/lib64 -lunwind -lparseAPI -lsymtabAPI -linstructionAPI -lcommon -L/usr/lib -ldwarf -lelf -L/usr/lib -lxml2 -o extrae extrae-extrae.o extrae-forkSnippets.o extrae-cudaSnippets.o extrae-ompSnippets.o extrae-apiSnippets.o extrae-mpiSnippets.o extrae-commonSnippets.o extrae-applicationType.o extrae-mini-xml-parse.o
libtool: link: g++ -I../../../src/common -I/usr/include -g -O2 -Wall -W -o extrae extrae-extrae.o extrae-forkSnippets.o extrae-cudaSnippets.o extrae-ompSnippets.o extrae-apiSnippets.o extrae-mpiSnippets.o extrae-commonSnippets.o extrae-applicationType.o extrae-mini-xml-parse.o -L/usr/lib64 -ldyninstAPI -lunwind -lparseAPI -lsymtabAPI -linstructionAPI -lcommon -L/usr/lib -ldwarf -lelf -lxml2
/usr/lib/libdynDwarf.so.8.1: undefined reference to `dwarf_elf_init'
/usr/lib/libdynDwarf.so.8.1: undefined reference to `dwarf_finish'
collect2: error: ld returned 1 exit status
make[4]: *** [extrae] Error 1
make[4]: Leaving directory `/root/src/extrae-2.3.4/src/launcher/dyninst'
This error is caused because libdynDwarf needs symbols that aren't included when the static library is linked. A solution to this is provided here, to replace:
-ldwarf
with:
-Wl,--whole-archive -ldwarf -Wl,--no-whole-archive
I make this change to:
./src/launcher/dyninst/Makefile.am
then configure and make again. I get this output:
/bin/sh ../../../libtool --tag=CXX --mode=link g++ -I../../../src/common -I/usr/include -g -O2 -Wall -W -L/usr/lib64 -ldyninstAPI -L/usr/lib64 -lunwind -lparseAPI -lsymtabAPI -linstructionAPI -lcommon -L/usr/lib -Wl,--whole-archive -ldwarf -Wl,--no-whole-archive -lelf -L/usr/lib -lxml2 -o extrae extrae-extrae.o extrae-forkSnippets.o extrae-cudaSnippets.o extrae-ompSnippets.o extrae-apiSnippets.o extrae-mpiSnippets.o extrae-commonSnippets.o extrae-applicationType.o extrae-mini-xml-parse.o
libtool: link: g++ -I../../../src/common -I/usr/include -g -O2 -Wall -W -Wl,--whole-archive -Wl,--no-whole-archive -o extrae extrae-extrae.o extrae-forkSnippets.o extrae-cudaSnippets.o extrae-ompSnippets.o extrae-apiSnippets.o extrae-mpiSnippets.o extrae-commonSnippets.o extrae-applicationType.o extrae-mini-xml-parse.o -L/usr/lib64 -ldyninstAPI -lunwind -lparseAPI -lsymtabAPI -linstructionAPI -lcommon -L/usr/lib -ldwarf -lelf -lxml2
/usr/lib/libdynDwarf.so.8.1: undefined reference to `dwarf_elf_init'
/usr/lib/libdynDwarf.so.8.1: undefined reference to `dwarf_finish'
Note that the liking ordering translated by libtool to (-ldwarf no longer wrapped by --whole-archive):
g++ ... -Wall -W -Wl,--whole-archive -Wl,--no-whole-archive -o extrae ... -ldyninstAPI ... -ldwarf ...
If I manually run the following two reordered commands, compilation succeeds and I can re-run make and it continues successfully.
g++ -I../../../src/common -I/usr/include -g -O2 -Wall -W -o load-module load_module-load-module.o -L/usr/lib64 -ldyninstAPI -lunwind -lparseAPI -lsymtabAPI -linstructionAPI -lcommon -L/usr/lib -Wl,--whole-archive -ldwarf -Wl,--no-whole-archive -lelf -lxml2
g++ -I../../../src/common -I/usr/include -g -O2 -Wall -W -o demo-launcher demo_launcher-demo-launcher.o -L/usr/lib64 -ldyninstAPI -lunwind -lparseAPI -lsymtabAPI -linstructionAPI -lcommon -L/usr/lib -Wl,--whole-archive -ldwarf -Wl,--no-whole-archive -lelf -lxml2
Question
how can I stop libtool reordering flags?
Is there a better solution?
Reference: Snipits of Makefile.am:
...
bin_PROGRAMS = extrae
...
extrae_SOURCES = extrae.C, ...
...
extrae_CXXFLAGS = -I$(COMMON_DIR)
extrae_CFLAGS = -I$(COMMON_DIR) -I#DYNINST_INCLUDES# #XML2_CFLAGS#
extrae_LDFLAGS = #DYNINST_LDFLAGS# -ldyninstAPI #UNWIND_LDFLAGS# #UNWIND_LIBS# -lparseAPI -lsymtabAPI -linstructionAPI $(DYNINST_EXTRA_LIBS) -lcommon #DWARF_LDFLAGS# -ldwarf #ELF_LDFLAGS# -lelf #XML2_LDFLAGS# #XML2_LIBS#
Related
So this is a snippet from my makefile to build my target:
#include header files directory
vpath %.h = include
vpath %.o = obj
#create a list of *.c from the source directory
SRC = $(wildcard src/*.c)
OBJ = $(SRC:src/%.c=%.o)
main.elf: $(OBJ)
$(CC) $(LDFLAGX) $(addprefix obj/,$(OBJ)) -o $#
%.o : %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $^ -o obj/$#
my project directory is as follows:
srcdir
+---include
+---obj
\---src
Here's the output I'm getting:
arm-none-eabi-gcc -Iinclude -mcpu=cortex-m3 -mthumb -std=gnu11 -O0 -g -Wall -c src/RCC.c -o obj/RCC.o
arm-none-eabi-gcc -Iinclude -mcpu=cortex-m3 -mthumb -std=gnu11 -O0 -g -Wall -c src/SPI.c -o obj/SPI.o
arm-none-eabi-gcc -Iinclude -mcpu=cortex-m3 -mthumb -std=gnu11 -O0 -g -Wall -c src/main.c -o obj/main.o
arm-none-eabi-gcc -Iinclude -mcpu=cortex-m3 -mthumb -std=gnu11 -O0 -g -Wall -c src/startup.c -o obj/startup.o
arm-none-eabi-gcc -Iinclude -mcpu=cortex-m3 -mthumb -std=gnu11 -O0 -g -Wall -c src/timer.c -o obj/timer.o
arm-none-eabi-gcc -Iinclude -mcpu=cortex-m3 -mthumb -std=gnu11 -O0 -g -Wall -c src/usart.c -o obj/usart.o
arm-none-eabi-gcc -Xlinker -T -Xlinker lscript.ld -Xlinker -nostdlib -Xlinker -Map=main.map obj/RCC.o obj/SPI.o obj/main.o obj/startup.o obj/timer.o obj/usart.o -o main.elf
c:/program files (x86)/gnu arm embedded toolchain/9 2020-q2-update/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: cannot find startup.o
collect2.exe: error: ld returned 1 exit status
make.exe": *** [main.elf] Error 1
So the startup.o exists in obj/ folder and the path has also been specified in the recipe so What is going wrong here?
I have been struggling to create my own makefile due to tons of such errors and even after trying out numerous tutorials and examples which may solve a problem, another new one pops up every now and then, is there any more convenient way to build such projects that does not cause me so much trouble?
Command used to link:
**libtool --tag=CC --mode=link gcc -I/usr/include/libxml2 -I/home/ovsdpdk/rpmbuild/BUILD/openvswitch-2.4.0.1/openvswitch-2.4.0/include/ -I/home/ovsdpdk/rpmbuild/BUILD/openvswitch-2.4.0.1/openvswitch-2.4.0/lib/ -O3 -lxml2 -lnetconf -lopenvswitch -lovsdb -lpthread -lcrypto -lssl -lrt -laio -avoid-version -module -shared -export-dynamic --mode=link -o ietf-interfaces.la .obj/ietf-interfaces.lo .obj/ovs_mediation.lo -rpath /usr/local/lib**
Error:
libtool: link: gcc -shared -fPIC -DPIC .obj/.libs/ietf-interfaces.o .obj/.libs/ovs_mediation.o -lxml2 -lnetconf -lopenvswitch -lovsdb -lpthread -lcrypto -lssl -lrt -laio -O3 -Wl,-soname -Wl,ietf-interfaces.so -o .libs/ietf-interfaces.so
/usr/bin/ld: /usr/local/lib/libopenvswitch.a(ovsdb-idl.o): relocation R_X86_64_TPOFF32 against `var.7533' can not be used when making a shared object; recompile with -fPIC
/usr/local/lib/libopenvswitch.a: could not read symbols: Bad value
collect2: error: ld returned 1 exit status
Trying to compile a C GTK gui + Prolog file using GPLC. I read that I can pass multiple flags to the gcc compiler from GPLC by using-C 'gcc flags here'
Ok so I can comiple my GUI alone with
gcc foo.c `pkg-config --cflags --libs gtk+-2.0` -o $(NAME)
However this will not work in GPLC because I would have
'`pkg-config --cflags --libs gtk+-2.0`'
This means I won't get the response from pkg-config as I am seeking because it is inside a "string". How can I fix that?
Lastly if I do something ugly like:
gplc -c foo1.c -C '-I/usr/include/gtk-2.0 -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include -I/usr/include/gio-unix-2.0/ -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/libpng12 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/freetype2 -lgtk-x11-2.0 -lgdk-x11-2.0 -lpangocairo-1.0 -latk-1.0 -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lpangoft2-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lfontconfig -lfreetype'
gplc -c foo2.pl
gplc foo1.o foo2.o -o gyges
I get compilation failure during linking due to all references to GTK functions being undefined. why?
Use shell in a Makefile:
GTK_FLAGS = $(shell pkg-config --cflags --libs gtk+-2.0)
gplc -c foo1.c -C $(GTK_FLAGS)
EDIT:
CC = gplc
GTK_CFLAGS = $(shell pkg-config --cflags gtk+-2.0)
GTK_LIBS = $(shell pkg-config --libs gtk+-2.0)
OBJECTS = foo1.o foo2.o
all: gyges
foo1.o: foo1.c
$(CC) -c foo1.c -o foo1.o $(GTK_CFLAGS)
foo2.o: foo2.pl
$(CC) -c foo2.pl -o foo2.o
gyges: $(OBJECTS)
$(CC) $(OBJECTS) -o gyges $(GTK_LIBS)
Answer
To solve the first problem I just needed to use shell inside a Makefile as Alter Mann pointed out.
The second problem was occurring because GPLC was not seeing the gtk libs during linking. This is because I was using the -C flag to pass args to the gcc compiler during compilation AND linking, this is incorrect, the -L flag is the flag that must be used to pass args to gcc during linking according to the gplc man.
So my final working MAKE looks likes this:
CC = gplc
GTK_CFLAGS = $(shell pkg-config --cflags gtk+-2.0)
GTK_LIBS = $(shell pkg-config --libs gtk+-2.0)
OBJECTS = foo1.o foo2.o
all: name
foo1.o:
$(CC) -c foo1.c -o foo1.o -C '$(GTK_CFLAGS)'
foo2.o:
$(CC) -c foo2.pl -o foo2.o
name: $(OBJECTS)
$(CC) $(OBJECTS) -o name -L '$(GTK_LIBS)'
rm *.o
I've a C GUI application (in GTK+2.0) that I used to link as follows :
gcc -O2 -std=gnu99 -pipe -Wall -lm `pkg-congig gtk+-2.0 `pkg-config --libs gtk+-2.0` -o exec a.o b.o c.o
which eventually converted into :
gcc -O2 -std=gnu99 -pipe -Wall -lm -pthread -I/usr/include/gtk-2.0 -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/pango-1.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/glib-2.0 -I/usr/lib/x86_64 linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgio-2.0 -lpangoft2-1.0 -lpangocairo-1.0 -lgdk_pixbuf-2.0 -lcairo -lpango-1.0 -lfreetype -lfontconfig -lgobject-2.0 -lglib-2.0 -lcairo -lgtk-x11-2.0 -lglib-2.0 -o exec a.o b.o c.o
It was until Ubuntu 12.04.
When I tried to link the files in the same way in Ubuntu 12.04 as well, it showed the following error :
/usr/bin/ld: b.o: undefined reference to symbol 'gdk_color_parse'
/usr/bin/ld: note: 'gdk_color_parse' is defined in DSO /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/libgdk-x11-2.0.so so try adding it to the linker command line
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/libgdk-x11-2.0.so: could not read symbols: Invalid operation
collect2: ld returned 1 exit status
If anyone has any idea about this please share.
With newer versions of GCC/binutils, linker flags have to come last because the linker looks ahead only for undefined symbols. Try
gcc -O2 -std=gnu99 -pipe -Wall a.o b.o c.o -lm `pkg-config --libs gtk+-2.0` -o exec
instead.
If I'm statically linking a GTK+ program under FreeBSD 8, gtk_builder_add_from_file() suddenly returns with an error:
Invalid object type `GtkWindow'
How to fix that? With dynamic linking everything works fine.
Update: linking is done by:
cc -o foobar foo.o bar.o main.o -Wall -pedantic -std=c99 D_THREAD_SAFE -DORBIT2=1 -D_REENTRANT -I/usr/local/include/gtk-2.0 -I/usr/local/lib/gtk-2.0/include -I/usr/local/include/atk-1.0 -I/usr/local/include/cairo -I/usr/local/include/pango-1.0 -I/usr/local/include -I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include -I/usr/local/include/pixman-1 -I/usr/local/include/freetype2 -I/usr/local/include/gconf/2 -I/usr/local/include/orbit-2.0 -I/usr/local/include/dbus-1.0 -I/usr/local/include/dbus-1.0/include -DGTK_DISABLE_DEPRECATED=1 -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DG_DISABLE_DEPRECATED=1 -DGTK_MULTIHEAD_SAFE=1 -export-dynamic -static -pthread -L/usr/local/lib -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangocairo-1.0 -lgio-2.0 -lXinerama -lXi -lXcursor -lXcomposite -lXdamage -lpangoft2-1.0 -lXext -lXfixes -lcairo -lpixman-1 -lpng -lxcb-render-util -lXrender -lxcb-render -lX11 -lxcb -lXau -lXdmcp -lpango-1.0 -lfontconfig -lexpat -lfreetype -lz -lgconf-2 -lORBit-2 -lm -ldbus-1 -lgmodule-2.0 -lgthread-2.0 -lgobject-2.0 -lglib-2.0 -liconv -lintl -lpcre
or in another words, in Makefile I have:
CFLAGS := -Wall -pedantic -std=c99
LDFLAGS := -export-dynamic -static
CFLAGS += $(shell pkg-config --cflags gtk+-2.0 gconf-2.0) \
-DGTK_DISABLE_DEPRECATED=1 -DGDK_DISABLE_DEPRECATED \
-DGDK_PIXBUF_DISABLE_DEPRECATED -DG_DISABLE_DEPRECATED=1 \
-DGTK_MULTIHEAD_SAFE=1
LDFLAGS += $(shell pkg-config --libs --static gtk+-2.0 gconf-2.0) -lintl -lpcre
...
$(NAME): $(OBJ)
cc -o $# $^ $(CFLAGS) $(LDFLAGS)
First of all linking gtk+ against an application statically is not supported. You are likely to run into a lot of hairy problems.
GtkBuilder needs to be able to dlopen your library, you need to make sure that all he symbols from the related libraries are also exported by your binary. On ELF systems you'll have to pass in the -export-dynamic/-Wl,-export-dynamic to the linker/gcc.