User Tools

Site Tools


developingpld:advanceddeveloping:fixingasneeded

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
developingpld:advanceddeveloping:fixingasneeded [2006-08-07 02:52]
SamChi - shorter examplex (removed my cflags)
developingpld:advanceddeveloping:fixingasneeded [2007-05-27 20:51] (current)
arekm
Line 4: Line 4:
  
  
-==== Quick Workaround ​==== +===== Quick and ugly workaround (DON'T USE IT!) ===== 
-Put in spec file this line+Put this line in ''​spec'' ​file: 
  
-<​file>​%devine filterout_ld -Wl,​--as-needed 
-</​file>​ 
-But **don'​t use it** unless you really need.  
  
-Why ? Because it's very stupid. If something fails to build normally ​it's a sign ''​--as-needed''​ did well it's job and disabled unneeded libraries. ​+ 
 +<​file>​%define filterout_ld -Wl,​--as-needed 
 +</​file>​ 
 +But **don't use it** unless you really need to quickly ​build a package. Never ever try to commit such a change. It might be tempting to do so but if you think about it ''​--as-needed''​ did it's job well and disabled unneeded libraries. If building fails, it's the package that needs to get fixed, not the linker flags
  
  
  
 ===== How --as-needed works ===== ===== How --as-needed works =====
-With ''​--as-needed''​ enabled only libraries ​which contain ​symbols required by __object files__ are linked. ​+With ''​--as-needed''​ enabledonly libraries ​containing ​symbols required by __object files__ are linked. ​
  
  
  
-== About positions ​== +==== Why it fails for some packages ==== 
-Linker options are positional, and position is very important. Because it looks for missing symbols ​only in libraries coming after object file+In other wordsif you list 10 libraries ​and only 3 of them contain referenced symbols, others are silently discarded. This is a good thing but unfortunately some projects fail to list all their dependencies properly
  
-Correct ​ones are: +This normally works because if project requires libraries //A// and //B// and //A// itself lists //B// as a dependency, both //A// and //B// get pulled in even if the project itself only lists //A//.  
 + 
 +Now assume that //A// is a superfluous (unneeded) dependency which gets dropped (or //A// requiring //B// is superfluous and //B// gets dropped from //A//). The symbols are no longer available.  
 + 
 + 
 + 
 +==== About positions ==== 
 +Linker options are positional, and position is very important. It looks for missing symbols only in libraries coming after object file.  
 + 
 +Correct ​positions ​are: 
  
 <​file>​$ gcc $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS) <​file>​$ gcc $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
Line 29: Line 38:
 and this generally works well.  and this generally works well. 
  
-If there is something like that: + 
 + If there is something like that: 
  
 <​file>​$ gcc -Wl,​--as-needed -l<​library>​ <​objects.o>​ <​file>​$ gcc -Wl,​--as-needed -l<​library>​ <​objects.o>​
Line 35: Line 45:
 the library will __never__ be linked, because it's not required at the time it's checked. ​ the library will __never__ be linked, because it's not required at the time it's checked. ​
  
-And with something like that: + 
 + And with something like that: 
  
 <​file>​$ gcc -l<​library>​ -Wl,​--as-needed <​objects.o>​ <​file>​$ gcc -l<​library>​ -Wl,​--as-needed <​objects.o>​
 </​file>​ </​file>​
-library will allways ​be linked, even if it's not required. ​+library will __allways__ ​be linked, even if it isn'required. ​
  
  
  
 ==== Short examples ==== ==== Short examples ====
-Most of problems are with readline/​ncurses and tinfo, and it's nice example: tinfo is required by both readline and ncurses, and both are linked with this library (now, when I'​ve ​[[http://​cvs.pld-linux.org/​cgi-bin/​cvsweb/​SOURCES/​readline-shared.patch?​r1=1.6&​amp;​r2=1.7|fixed readline]];). +Most of problems are with readline/​ncurses and tinfo, and it's nice example: tinfo is required by both readline and ncurses, and both are linked with this library (now, when [[http://​cvs.pld-linux.org/​cgi-bin/​cvsweb/​SOURCES/​readline-shared.patch?​r1=1.6&​amp;​r2=1.7|fixed readline]] ​is fixed). 
  
-But some packages link with readline or ncurses while they use __only__ symbols from tinfo. ​ //Without// ''​--as-needed''​ those executables work because they are linked with tinfo from readline/​ncurses library. ​ //With// ''​--as-needed'' ​it will not work, because readline/​ncurses contain no symbols required by executable so they are not linked, it's dependencies naturally are neither linked. Thats why there is a need to pass ''​-ltinfo''​. If it requires only symbols from tinfo it's ok to ''​s/​ncurses/​tinfo/''​. But if it really requires readline/​ncurses but there is some executable (or ./​configure) which requires only tinfo both ''​-lreadline''/''​-lncurses''​ and ''​-ltinfo''​ should be passed. ​+But some packages link with readline or ncurses while they use __only__ symbols from tinfo. //Without// ''​--as-needed''​ those executables work because they are linked with tinfo from readline/​ncurses library. //With// ''​--as-needed'' ​linking ​will not work, because readline/​ncurses contain no symbols required by executable so they are not linked, it's dependencies naturally are neither linked. Thats why there is a need to pass ''​-ltinfo''​. If it requires only symbols from tinfo it's ok to ''​s/​ncurses/​tinfo/''​. But if it really requires readline/​ncurses but there is some executable (or ./​configure) which requires only tinfo both ''​-lreadline''/''​-lncurses''​ and ''​-ltinfo''​ should be passed. ​
  
 For a longer example take a look at real example nr. 1.  For a longer example take a look at real example nr. 1. 
Line 59: Line 70:
 <​file>​$ gcc -Wl,​--as-needed -o executable <​objects.o>​ -l2 -l1 <​file>​$ gcc -Wl,​--as-needed -o executable <​objects.o>​ -l2 -l1
 </​file>​ </​file>​
-it's usual when object files require only library 2, and -l1 is required by -l2. As I said linker only checks for symbols from objects, so -l1 is not linked. Normally it is easy to fix it, simply make sure while linking -l2 it is linked to -l1 (take a look at the second real example). ​+It's usual situation ​when object files require only library 2, and //-l1// is required by //-l2//. As I said linker only checks for symbols from objects, so //-l1// is not linked. Normally it is easy to fix it, simply make sure while linking ​//-l2// it is linked to //-l1// (take a look at the second real example). ​
  
  
Line 73: Line 84:
  
  
-<​file>​x86_64-pld-linux-g++ -DNOMMGR -Wall -DGAMEDATADIR=\"/​usr/​share/​xmoto\" ​ -ggdb -O2 -Wl,​--as-needed -o xmoto-edit ​ BuiltInFont.o [...object files...] Packager.o -lGL -lcurl -lode -llualib50 -llua50 -lSDL_mixer -lbz2 -lz -lpng -ljpeg+<​file>​g++ -Wl,​--as-needed -o xmoto-edit BuiltInFont.o [...object files...] Packager.o -lGL -lcurl -lode -llualib50 -llua50 -lSDL_mixer -lbz2 -lz -lpng -ljpeg
  
 VApp.o: In function `vapp::​App::​getRealTime()':​ VApp.o: In function `vapp::​App::​getRealTime()':​
Line 98: Line 109:
 Binary file /​usr/​lib64/​libSDL.so matches Binary file /​usr/​lib64/​libSDL.so matches
 </​file>​ </​file>​
-they are in ''​-lSDL'',​ but binary does not link with ''​-lSDL''​; edit Makefile by hand and add ''​-lSDL''​ at the same place ''​-lSDL_mixer''​ is: ''​LIBS = -lcurl -lode -llualib50 -llua50 -lSDL_mixer -lSDL -lbz2 -lz -lpng -ljpeg'' ​+They are in ''​-lSDL'',​ but binary does not link with ''​-lSDL''​. Edit Makefile by hand and add ''​-lSDL''​ at the same place ''​-lSDL_mixer''​ is: ''​LIBS = -lcurl -lode -llualib50 -llua50 -lSDL_mixer -lSDL -lbz2 -lz -lpng -ljpeg'' ​
  
 What we get after running make in build tree:  What we get after running make in build tree: 
Line 104: Line 115:
  
  
-<​file>​x86_64-pld-linux-g++ -DNOMMGR -Wall -DGAMEDATADIR=\"/​usr/​share/​xmoto\"​ -ggdb -O2 -Wl,​--as-needed -o xmoto-edit BuiltInFont.o [...object files...] Packager.o ​ -lcurl -lode -llualib50 -llua50 -lSDL_mixer -lSDL -lbz2 -lz -lpng -ljpeg ​+<​file>​g++ -Wl,​--as-needed -o xmoto-edit BuiltInFont.o [...object files...] Packager.o -lcurl -lode -llualib50 -llua50 -lSDL_mixer -lSDL -lbz2 -lz -lpng -ljpeg
  
 VApp.o: In function `vapp::​App::​grabScreen()':​ VApp.o: In function `vapp::​App::​grabScreen()':​
Line 137: Line 148:
  
  
-<​file>​x86_64-pld-linux-g++ -DNOMMGR -Wall -DGAMEDATADIR=\"/​usr/​share/​xmoto\" ​ -ggdb -O2 -Wl,​--as-needed -o xmoto-edit ​ BuiltInFont.o [...object files...] Packager.o ​ -lcurl -lode -llualib50 -llua50 -lSDL_mixer -lSDL -lGL -lbz2 -lz -lpng -ljpeg+<​file>​g++ -Wl,​--as-needed -o xmoto-edit BuiltInFont.o [...object files...] Packager.o -lcurl -lode -llualib50 -llua50 -lSDL_mixer -lSDL -lGL -lbz2 -lz -lpng -ljpeg
  
 make[1]: Leaving directory `/​home/​users/​sparky/​rpm/​BUILD/​xmoto-0.2.0'​ make[1]: Leaving directory `/​home/​users/​sparky/​rpm/​BUILD/​xmoto-0.2.0'​
 </​file>​ </​file>​
-//It worked !// +**It worked !** 
  
  
Line 178: Line 189:
  
  
-<​file>/​bin/​sh ../libtool --tag=CC --mode=link ​x86_64-pld-linux-gcc -ggdb -O2 -Wall  ​-Wl,​--as-needed -o test-source-selector ​ test-source-selector.o libedataserverui-1.2.la ../​libedataserver/​libedataserver-1.2.la -pthread -lglade-2.0 [...many -l libraries...] ​+<​file>/​bin/​sh ../libtool --tag=CC --mode=link gcc -Wl,​--as-needed -o test-source-selector ​ test-source-selector.o libedataserverui-1.2.la ../​libedataserver/​libedataserver-1.2.la -pthread -lglade-2.0 [...many -l libraries...]
 -lgnome-keyring -lpthread -lgnome-keyring -lpthread
  
-x86_64-pld-linux-gcc -ggdb -O2 -Wall -Wl,​--as-needed -o .libs/​test-source-selector test-source-selector.o -pthread ./​.libs/​libedataserverui-1.2.so [many, many .so and -l libraries] -lpthread+gcc -Wl,​--as-needed -o .libs/​test-source-selector test-source-selector.o -pthread ./​.libs/​libedataserverui-1.2.so [...many, many .so and -l libraries...] -lpthread
  
 ./​.libs/​libedataserverui-1.2.so:​ undefined reference to `glade_xml_new'​ ./​.libs/​libedataserverui-1.2.so:​ undefined reference to `glade_xml_new'​
Line 210: Line 221:
 ''​GNOME_KEYRING_LIBS = -lgnome-keyring -lglib-2.0'' ​ ''​GNOME_KEYRING_LIBS = -lgnome-keyring -lglib-2.0'' ​
  
-So add this one and glade to that library deps: +So add this one and ''​-lglade-2.0'' ​to that library deps: 
  
  
Line 233: Line 244:
  
 == Why was it working without --as-needed ? == == Why was it working without --as-needed ? ==
-test-source-selector binary was linked with all libraries needed by libedataserverui-1.2.so,​ and the binary was the one who provided missing symbols to libedataserverui-1.2.so ​+''​test-source-selector'' ​binary was linked with all libraries needed by libedataserverui-1.2.so,​ and the binary was the one who provided missing symbols to libedataserverui-1.2.so ​ 
 + 
 + 
 + 
 +=== What if broken library comes from other package ? === 
 +You can check manually does library has all required symbols, simply running ' gcc //library// ', like this:  
 + 
 +This is an example of correctly linked library:  
 + 
 +<​file>​$ gcc /​usr/​lib64/​liblftp-tasks.so.0.0.0 
 +/​usr/​lib64/​gcc/​x86_64-pld-linux/​4.1.2/​../​../​../​../​lib64/​crt1.o:​ In function `_start':​ 
 +(.text+0x20):​ undefined reference to `main'​ 
 +collect2: ld returned 1 exit status 
 +</​file>​ 
 +And incorrectly linked one:  
 + 
 +<​file>​$ gcc /​usr/​lib64/​liblftp-jobs.so.0.0.0 
 +/​usr/​lib64/​gcc/​x86_64-pld-linux/​4.1.2/​../​../​../​../​lib64/​crt1.o:​ In function `_start':​ 
 +(.text+0x20):​ undefined reference to `main'​ 
 +/​usr/​lib64/​liblftp-jobs.so.0.0.0:​ undefined reference to `StringSet::​Remove(int)'​ 
 +/​usr/​lib64/​liblftp-jobs.so.0.0.0:​ undefined reference to `Buffer::​Format(char const*, ...)'​ 
 +[...] 
 +/​usr/​lib64/​liblftp-jobs.so.0.0.0:​ undefined reference to `SMTask::​SuspendSlave()'​ 
 +collect2: ld returned 1 exit status 
 +</​file>​ 
 +**Warning:​** some libraries may require to have unresolved symbols. ​
  
  
  
 ==== 3. unresolved symbols caused by incorrect order ==== ==== 3. unresolved symbols caused by incorrect order ====
-Two of most difficult of common problems at once,  [[http://​cvs.pld-linux.org/​cgi-bin/​cvsweb/​SPECS/​evolution.spec?​rev=HEAD|evolution.spec]]: ​+Two of most difficult of common problems at once, [[http://​cvs.pld-linux.org/​cgi-bin/​cvsweb/​SPECS/​evolution.spec?​rev=HEAD|evolution.spec]]: ​
  
 The difficulties are:  The difficulties are: 
Line 256: Line 292:
  
  
-<​file>​x86_64-pld-linux-gcc -o conftest -ggdb -O2 -DORBIT2=1 -pthread -I/​usr/​include/​libgnome-2.0 [...many -I...] -I/​usr/​include/​libxml2 -Wl,​--as-needed -pthread -lgpilotd [...many -l...] -lglib-2.0 conftest.c >&5+<​file>​gcc -o conftest -ggdb -O2 -DORBIT2=1 -pthread -I/​usr/​include/​libgnome-2.0 [...many -I...] -I/​usr/​include/​libxml2 -Wl,​--as-needed -pthread -lgpilotd [...many -l...] -lglib-2.0 conftest.c >&5
  
 /​home/​users/​sparky/​tmp/​ccgrL9ll.o:​ In function `main':​ /​home/​users/​sparky/​tmp/​ccgrL9ll.o:​ In function `main':​
Line 263: Line 299:
 collect2: ld returned 1 exit status collect2: ld returned 1 exit status
 </​file>​ </​file>​
-function '''​convert_ToPilotChar''',​ may be found in passed library, but take a look at section about positions, arguments order is incorrect: libraries go before objects (conftest.c) ​it's very common when someone puts ''​-l<>''​ in ''​LDFLAGS''​ instead of ''​LIBS'',​ that was the case too +function '''​convert_ToPilotChar''',​ may be found in passed library, but take a look at section about positions, arguments order is incorrect: libraries go before objects (conftest.c). It's very common when someone puts ''​-l<>''​ in ''​LDFLAGS''​ instead of ''​LIBS'',​ that was the case too
  
-just take a look at my fix: +Just take a look at my fix: 
  
  
Line 277: Line 313:
 +       ​LIBS="​$LIBS_save"​ +       ​LIBS="​$LIBS_save"​
 </​file>​ </​file>​
-with this simple change everything works perfectly. ​+With this simple change everything works perfectly. ​
  
  
developingpld/advanceddeveloping/fixingasneeded.1154911924.txt.gz · Last modified: 2006-08-07 02:52 by SamChi