OpenSDE Framework (without history before r20070)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

886 lines
27 KiB

  1. #!/bin/bash
  2. #
  3. # --- NO-ROCK-COPYRIGHT-NOTE ---
  4. #
  5. # Found in the debian boot-floppies source package from:
  6. # http://www.kernel.org/debian/dists/potato/main/source/admin/
  7. #
  8. # mklibs.sh: An automated way to create a minimal /lib/ directory.
  9. #
  10. # Copyright 1999 by Marcus Brinkmann <Marcus.Brinkmann@ruhr-uni-bochum.de>
  11. #
  12. # This program is free software; you can redistribute it and/or modify
  13. # it under the terms of the GNU General Public License as published by
  14. # the Free Software Foundation; either version 2 of the License, or
  15. # (at your option) any later version.
  16. #
  17. # This program is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. # GNU General Public License for more details.
  21. #
  22. # You should have received a copy of the GNU General Public License
  23. # along with this program; if not, write to the Free Software
  24. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25. #
  26. # Introduction:
  27. # When creating boot floppies, there is never enough room on the disks.
  28. # So it is important not to waste bytes on unnecessary code.
  29. # Shared Libraries contain many functions that are probably not used in the
  30. # binaries included in the boot disks, and copying the whole library is a
  31. # waste of space.
  32. # This utilitiy helps to reduce the necessary libraries to only include the
  33. # symbols needed to run a given set of executables.
  34. #
  35. # Features:
  36. # * Automatic detection of all necessary libraries, even for inter-library
  37. # dependencies, for a given set of executables.
  38. # * Automatic installation of all needed libraries and soname links.
  39. # * Automatic reduction of all libraries to minimal size for which PIC
  40. # libraries are provided.
  41. #
  42. # Requirements:
  43. # * Beside the shared libraries, you need libfoo_pic.a files for all
  44. # libraries you want to reduce.
  45. # * You need binutils (notably objdump and objcopy) installed.
  46. # A GENERAL NOTE ABOUT LANGUAGE ABUSE
  47. #
  48. # If you believe this program had better not been written in shell script
  49. # language, I invite you to reimplement it in the language of your
  50. # preference.
  51. # The reasons I chose shell are:
  52. # * Shell scripts are very portable and available even on minimal systems as
  53. # well as boot disks.
  54. # * Shell scripts can be run without compilation.
  55. # * Shell scripts provide a very easy interface to the various system
  56. # commands I need to get the library dependencies and sort through them.
  57. # Perl is lacking good data types, so implementing this would be equally
  58. # cumbersome in perl (I need trees and queues, for example).
  59. # C and C++ are lacking easy access to the system commands.
  60. #
  61. # Of course, shell scripting has many problems:
  62. # * Use of temporary files for string arrays.
  63. # * Slow.
  64. # * Hard to debug.
  65. #
  66. # I think for hand written code, I hit a limit with the size and execution
  67. # time of this program of what is still acceptable as a shell script. I also
  68. # tried to improve the situation with many comments.
  69. # TODO:
  70. # * Make sure versioned symbols get correct version number.
  71. # This seems to work now, however, we always include
  72. # all versions of a symbol. This is not a problem. To do
  73. # it properly, we had to parse the version information in
  74. # objdump, which is hard.
  75. # * Use --dynamic-syms on so lib instead --syms on pic file.
  76. # * Autodetect that libc needs ld (should be possible from
  77. # output of objdump --privat-headers| grep NEEDD).
  78. # * Code to create libs in cycles !!!
  79. # HISTORY:
  80. #
  81. # 1999-09-13 Marcus Brinkmann <brinkmd@debian.org>
  82. #
  83. # * Initial release (v0.1).
  84. #
  85. # STATIC DATA SECTION
  86. #
  87. usage="Usage: $0 [OPTION]... -d DEST FILE ..."
  88. try="Try "\`"$0 --help' for more information"
  89. version="$0 0.1, Copyright 1999 Marcus Brinkmann"
  90. PATH=/bin:/usr/bin
  91. default_src_path=/lib:/usr/lib
  92. dest=
  93. exec=
  94. action=
  95. verbose="false"
  96. gcc=${GCC-gcc}
  97. objdump=${OBJDUMP-objdump}
  98. objcopy=${OBJCOPY-objcopy}
  99. # =================
  100. # GRAPH ABSTRACTION
  101. # =================
  102. #
  103. # Because we do some hairy graph operations, we provide some
  104. # abstractions of them. Some functions here are very simple, but
  105. # the source is much more readable this way.
  106. # check-node NODE ...
  107. # checks if all NODEs are valid node names.
  108. # Used internally for verificaton only.
  109. # Return 0 if all NODEs are valid.
  110. # Currently, a node is valid if it does not contain a space.
  111. check-node () {
  112. local node
  113. for node in "$@" ; do
  114. if [ "x`echo $node | sed -e '/ /d'`" = x ] ; then
  115. echo 1>&2 $0: check-node: invalid node \"$node\"
  116. exit 1
  117. fi
  118. done
  119. return 0
  120. }
  121. # is-graph FILE ...
  122. # provides a very simple type assertion
  123. # Turns FILE into a graph if it isn't already and returns 0.
  124. is-graph () {
  125. local file
  126. for file in "$@" ; do
  127. if [ ! -e "$file" ] ; then
  128. touch "$qfile"
  129. fi
  130. done
  131. }
  132. # add-node FILE NODE
  133. # add a node NODE to graph FILE.
  134. # This is useful if you need to make sure that a node appears
  135. # in the graph without actually connecting it to an arrow.
  136. # You don't need to add nodes that are part of an arrow.
  137. add-node () {
  138. if [ $# != 2 ] ; then
  139. echo 1>&2 $0: add-node: internal error: called with invalid number of arguments
  140. exit 1
  141. fi
  142. check-node "$2"
  143. echo "$2 $2" >> "$1"
  144. return 0
  145. }
  146. # add-arrow FILE NODE1 NODE2
  147. # add an arrow from NODE1 to NODE2 to graph FILE.
  148. add-arrow () {
  149. if [ $# != 3 ] ; then
  150. echo 1>&2 $0: add-arrow: internal error: called with invalid number of arguments
  151. exit 1
  152. fi
  153. check-node "$2" "$3"
  154. echo "$2 $3" >> "$1"
  155. return 0
  156. }
  157. # find-cycle FILE
  158. # finds a cycle in a graph FILE.
  159. # If a cycle is found, it is printed out at stdin, one node each line,
  160. # and 0 is returned. Otherwise, nothing is printed on stdout and exit
  161. # status is 1.
  162. find-cycle () {
  163. if [ $# != 1 ] ; then
  164. echo 1>&2 $0: find-cycle: internal error: called with invalid number of arguments
  165. exit 1
  166. fi
  167. tsort "$1" 2> "$fl_dir/find-cycle" > /dev/null
  168. if [ "x`cat $fl_dir/find-cycle`" = x ] ; then
  169. return 1
  170. else
  171. if [ "x`head -n 1 $fl_dir/find-cycle`" != "xtsort: cycle in data" ] ; then
  172. echo 1>&2 $0: find-cycle: internal error: tsort has invalid output format
  173. exit 1
  174. fi
  175. cat "$fl_dir/find-cycle" | sed -e '1d' -e '/tsort: cycle in data/,$d' -e 's/^tsort: //'
  176. fi
  177. }
  178. # shrink-nodes FILE NODE1 ...
  179. # shrinks several nodes NODE1 ... to a single node in graph FILE.
  180. # To hide cycles, we treat a cycle as a single node and replace
  181. # each occurence of a node in the cycle with a new node
  182. # [NODE1,...] . This change is destructive and can not be undone!
  183. # (You would need to store the entry point to the cycle for each arrow
  184. # pointing to/from it).
  185. # This function does not check if the the nodes NODE1 ... exist.
  186. # However, if none of these nodes exists already, the new node will
  187. # not appear either. This makes this function sort of idem potent.
  188. # It does not check if NODE1 ... are a cycle. We will assume this
  189. # later in the library dependency analysis, but nothing in the code
  190. # relies on it.
  191. # Always shrink all cycles, or you may get unresolved symbols.
  192. #
  193. # Example:
  194. # N1 ---> N2 N1 -------> /------------\
  195. # | "shrink-nodes N2 N4" | _ | [N2,N4] |
  196. # v -------------------> v _____/| \------------/
  197. # N3 ---> N4 N3 /
  198. # A small helper function will aid us...
  199. # equal-match STRING STRING1 ...
  200. # return 0 if STRING is among STRING1 ..., 1 otherwise.
  201. equal-match () {
  202. local string
  203. local stringk
  204. string="$1"
  205. shift
  206. for stringk in "$@" ; do
  207. if [ "x$string" = "x$stringk" ] ; then
  208. return 0
  209. fi
  210. done
  211. return 1
  212. }
  213. shrink-nodes () {
  214. local head
  215. local lnode
  216. local rnode
  217. local graph="$1"
  218. shift
  219. is-graph "$graph"
  220. check-node "$@"
  221. local cnode="[`echo "$@" | sed 's/ /,/g'`]"
  222. # Okay, it's a hack. We treat the graph as a queue. I am just too
  223. # lazy to copy the relevant code here. Of course, we exploit several
  224. # properties of the graph and queue file format here (for example,
  225. # that graphs never can contain a QUEUE_SEPERATOR, and that a graph is
  226. # really a simple file with "a b" entries).
  227. cat /dev/null > "$fl_dir/shrink-cycle"
  228. while head=`get-top-of-queue "$graph"` ; do
  229. lnode=`echo $head|sed 's/ [^ ]*$//'`
  230. if equal-match "$lnode" "$@" ; then
  231. lnode="$cnode"
  232. fi
  233. rnode=`echo $head|sed 's/^[^ ]* //'`
  234. if equal-match "$rnode" "$@" ; then
  235. rnode="$cnode"
  236. fi
  237. echo "$lnode $rnode" >> "$fl_dir/shrink-cycle"
  238. done
  239. cat "$fl_dir/shrink-cycle" | sort -u > "$graph"
  240. }
  241. # =================
  242. # QUEUE ABSTRACTION
  243. # =================
  244. #
  245. # I added an abstract interface for queues to make the code more readable.
  246. # Queue operations usually consist of several atomic file operations, which
  247. # can get quite messy.
  248. #
  249. # You can use queues to simply loop through all lines of a file, but you
  250. # also can add stuff to the queue while processing it.
  251. #
  252. # Implementation: All queues consist of a QUEUE_FILE which has two parts:
  253. # the remaining entries in the queue (QUEUE) and the already processed
  254. # entries (BUCKET).
  255. # The two parts are seperated by a line containing only QUEUE_SEPERATOR.
  256. QUEUE_SEPERATOR=SEPERATOR___ABOVE_IS_QUEUE__BELOW_IS_BUCKET___SEPERATOR
  257. # check-queue-entry QENTRY ...
  258. # checks if all queue entries QENTRY are valid.
  259. # Used internally for verificaton only.
  260. # Return 0 if all QENTRYs are valid.
  261. # Currently, a node is valid if it does not match the QUEUE_SEPERATOR.
  262. check-queue-entry () {
  263. local qentry
  264. for qentry in "$@" ; do
  265. if [ "x`echo $qentry | sed "/^$QUEUE_SEPERATOR$/d"`" = x ] ; then
  266. echo 1>&2 $0: check-queue-entry: invalid qentry name \"$qentry\"
  267. exit 1
  268. fi
  269. done
  270. return 0
  271. }
  272. # is-queue QUEUE_FILE ...
  273. # provides a very simple type assertion
  274. # Turns QUEUE_FILE into a queue if it isn't already and returns 0.
  275. is-queue () {
  276. local qfile
  277. for qfile in "$@" ; do
  278. if [ ! -e "$qfile" ] ; then
  279. echo "$QUEUE_SEPERATOR" > "$qfile"
  280. else
  281. if ! grep -q "^$QUEUE_SEPERATOR$" "$qfile" ; then
  282. echo "$QUEUE_SEPERATOR" >> "$qfile";
  283. fi
  284. fi
  285. done
  286. }
  287. # get-top-of-queue QUEUE_FILE
  288. # processes a queue one more time.
  289. # If QUEUE of QUEUE_FILE is empty, exit status is 1 and no output is given.
  290. # Otherwise, top of QUEUE is removed, returned on stdout and
  291. # appended to the end of the BUCKET part of QUEUE_FILE.
  292. get-top-of-queue () {
  293. if [ $# != 1 ] ; then
  294. echo 1>&2 $0: get-top-of-queue: internal error: called with invalid number of arguments
  295. exit 1
  296. fi
  297. is-queue "$1"
  298. local head=`head -n 1 "$1"`
  299. if [ "x$head" = "x$QUEUE_SEPERATOR" ] ; then
  300. return 1
  301. else
  302. sed -e 1d "$1" > "$fl_dir/get-top-of-queue"
  303. echo "$head" | tee --append "$fl_dir/get-top-of-queue"
  304. cat "$fl_dir/get-top-of-queue" > "$1"
  305. return 0
  306. fi
  307. }
  308. # add-to-queue-if-not-there QUEUE_FILE QENTRY ...
  309. # add queue entries QENTRY ... to the beginning of the
  310. # QUEUE of QUEUE_FILE if it is neither in QUEUE nor in BUCKET
  311. # of QUEUE_FILE.
  312. # Return with exit status 0.
  313. # Note: If you want to add QENTRY to the *end* of QUEUE, you would do
  314. # something like the following:
  315. # sed -e s/^$QUEUE_SEPERATOR$/$head"'\
  316. # '"$QUEUE_SEPERATOR/"
  317. # which is necessary to pass the newline to sed. I think we can take the
  318. # easy way out.
  319. add-to-queue-if-not-there () {
  320. local qentry
  321. local qfile="$1"
  322. shift
  323. check-queue-entry "$@"
  324. is-queue "$qfile"
  325. for qentry in "$@" ; do
  326. if ! grep -q "^$qentry\$" "$qfile" ; then
  327. echo "$qentry" > "$fl_dir/add-to-queue-if-not-there"
  328. cat "$qfile" >> "$fl_dir/add-to-queue-if-not-there"
  329. cat "$fl_dir/add-to-queue-if-not-there" > "$qfile"
  330. fi
  331. done
  332. return 0
  333. }
  334. # ==================
  335. # LIBRARY PROCESSING
  336. # ==================
  337. #
  338. # The following helper functions mess around with the actual
  339. # processing and installation of libraries.
  340. #
  341. # get-library-depends OBJ1 ...
  342. # get all libraries the objects OBJ1 ... depend on.
  343. # OBJs can be binaries or shared libraries.
  344. # The list is neither sort'ed nor uniq'ed.
  345. get-library-depends () {
  346. if [ $# = 0 ] ; then
  347. echo 1>&2 $0: get-library-depends: internal error: no arguments
  348. exit 1
  349. fi
  350. $objdump --private-headers "$@" 2> /dev/null \
  351. | sed -n 's/^ *NEEDED *\([^ ]*\)$/\1/p'
  352. }
  353. # get-undefined-symbols OBJ1 ...
  354. # get all unresolved symbols in OBJ1 ...
  355. # The list is neither sort'ed nor uniq'ed.
  356. get-undefined-symbols () {
  357. if [ $# = 0 ] ; then
  358. echo 1>&2 $0: get-undefined-symbols: internal error: no arguments
  359. exit 1
  360. fi
  361. # ash has undefined reference to sys_siglist if .bss is not mentioned
  362. # here. Reported by Joel Klecker.
  363. # All symbols are epxosed, so we just catch all. Suggested by Roland
  364. # McGrath. Another thing to try is to investigate --dynamic-reloc.
  365. $objdump --dynamic-syms "$@" 2> /dev/null \
  366. | sed -n 's/^.* \([^ ]*\)$/\1/p'
  367. # | sed -n 's/^.*[\*UND\*|.bss].* \([^ ]*\)$/\1/p'
  368. }
  369. # get-provided-symbols LIB1 LIB2 ...
  370. # get all symbols available from libraries LIB1 ... .
  371. # Does only work for pic libraries.
  372. #
  373. # v Watch the tab stop here.
  374. # 00000000 w F .text 00000000 syscall_device_write_request
  375. # 00000000 g F .text 0000056c __strtoq_internal
  376. get-provided-symbols () {
  377. if [ $# = 0 ] ; then
  378. echo 1>&2 $0: get-provided-symbols: internal error: no arguments
  379. exit 1
  380. fi
  381. $objdump --syms "$@" 2>/dev/null | grep -v '\*UND\*' \
  382. | sed -n 's/^[0-9a-f]\+ \(g \| w\) .. .* [0-9a-f]\+ \(0x8[08]\)\? *\([^ ]*\)$/\3/p'
  383. }
  384. # Crude hack (?) only used for diagnostic.
  385. get-provided-symbols-of-so-lib () {
  386. if [ $# = 0 ] ; then
  387. echo 1>&2 $0: get-provided-symbols: internal error: no arguments
  388. exit 1
  389. fi
  390. $objdump --dynamic-syms "$@" 2>/dev/null \
  391. | sed -e '/\*UND\*/d' | sed -n 's/^.* \([^ ]*\)$/\1/p'
  392. }
  393. # get-common-symbols FILE1 FILE2
  394. # returns a list of all symbols in FILE1 that appear also in FILE2
  395. # Note: When get-common-symbols returns, FILE1 and FILE2 are "sort -u"'ed.
  396. # Note: Version Information in FILE1 is ignored when comparing.
  397. get-common-symbols () {
  398. if [ $# != 2 ] ; then
  399. echo 1>&2 $0: get-common-symbols: internal error: called with invalid number of arguments
  400. exit 1
  401. fi
  402. # Not needed anymore, but we go for compatibility.
  403. # (Somewhere we HAVE to clean FILE2 up).
  404. sort -u "$1" > $fl_dir/get-common-symbols
  405. cat $fl_dir/get-common-symbols > "$1"
  406. sort -u "$2" > $fl_dir/get-common-symbols
  407. cat $fl_dir/get-common-symbols > "$2"
  408. local symbol=
  409. while symbol=`get-top-of-queue $fl_dir/get-common-symbols` ; do
  410. grep ^$symbol\$\\\|^$symbol@ "$1"
  411. done
  412. }
  413. # create-link TARGET LINK_NAME
  414. # creates a soft link if there isn't one already.
  415. create-link () {
  416. if [ $# != 2 ] ; then
  417. echo 1>&2 $0: create-link: internal error: called with invalid number of arguments
  418. exit 1
  419. fi
  420. if [ ! -e "$2" ] ; then
  421. $action ln -s "$1" "$2"
  422. fi
  423. }
  424. # find-file PATH FILE
  425. # search all directories in PATH for file FILE, return absolute path
  426. # FILE can be a relative path and a filename.
  427. # PATH is a list, seperator is ':'.
  428. find-file () {
  429. if [ $# != 2 ] ; then
  430. echo 1>&2 $0: find-file: internal error: exactly two arguments required
  431. exit 1
  432. fi
  433. local path=$1
  434. local dir=`echo $path | sed -e 's/:.*$//'`
  435. until [ "x$path" = x ] ; do
  436. if [ "x$dir" != x ] ; then
  437. if [ -e "$dir/$2" ] ; then
  438. echo "$dir/$2"
  439. return 0
  440. fi
  441. fi
  442. path=`echo $path | sed -e 's/^[^:]*:*//'`
  443. dir=`echo $path | sed -e 's/:.*$//'`
  444. done
  445. return 1
  446. }
  447. # find-files PATH FILE1 FILE2 ...
  448. # search all directories in PATH for file FILE1, FILE2...
  449. # FILE can be a relative path and a filename.
  450. # PATH is a list, seperator is ':'.
  451. # Return value is a white space seperated list of absolute filenames.
  452. find-files () {
  453. if [ $# -lt 2 ] ; then
  454. echo 1>&2 $0: find-files: internal error: too few arguments
  455. exit 1
  456. fi
  457. local path="$1" ; shift
  458. while [ $# != 0 ] ; do
  459. find-file $path $1
  460. shift
  461. done
  462. }
  463. # get-pic-file LIB
  464. # returns the filename of the pic archive for LIB.
  465. # Note: There doesn't seem to be any convention, *ick*.
  466. get-pic-file () {
  467. if [ $# != 1 ] ; then
  468. echo 1>&2 $0: get-pic-file: internal error: called with invalid number of arguments
  469. exit 1
  470. fi
  471. if [ "x$1" = "xlibc-2.0.7.so" ] ; then
  472. # Order does matter! First init, then lib, then fini!
  473. echo `find-files $src_path libc_pic/soinit.so libc_pic.a libc_pic/sofini.so`
  474. return 0
  475. fi
  476. if [ "x$1" = "xlibc-2.1.2.so" -o "x$1" = "xlibc-2.1.3.so" \
  477. -o "x$1" = "xlibc-2.2.so" -o "x$1" = "xlibc-2.2.1.so" \
  478. -o "x$1" = "xlibc-2.2.2.so" ] ; then
  479. # Order does matter! First init, then lib, then fini!
  480. echo `find-files $src_path libc_pic/soinit.o libc_pic.a libc_pic/sofini.o libc_pic/interp.o`
  481. return 0
  482. fi
  483. if [ "x$1" = "xlibm-2.1.2.so" -o "x$1" = "xlibm-2.1.3.so" \
  484. -o "x$1" = "xlibm-2.2.so" -o "x$1" = "xlibm-2.2.1.so" \
  485. -o "x$1" = "xlibm-2.2.2.so" ] ; then
  486. echo `find-file "$src_path" libm_pic.a`
  487. return 0
  488. fi
  489. if [ "x$1" = "xlibslang.so.1.3.9" ] ; then
  490. echo `find-file $src_path libslang1.3.9_pic.a`
  491. return 0
  492. fi
  493. if [ "x$1" = "xlibslang.so.1.4.1" ] ; then
  494. echo `find-file $src_path libslang1.4.1_pic.a`
  495. return 0
  496. fi
  497. local libname=`echo $1 | sed -e 's/^lib\(.*\).so.*/\1/'`
  498. echo `find-file "$src_path" lib${libname}_pic.a`
  499. return 0
  500. }
  501. get-extra-flags () {
  502. if [ $# != 1 ] ; then
  503. echo 1>&2 $0: get-extra-flags: internal error: called with invalid number of arguments
  504. exit 1
  505. fi
  506. if [ "x$1" = "xlibc-2.0.7.so" ] ; then
  507. echo `find-file $src_path ld-2.0.7.so` -lgcc
  508. return 0
  509. fi
  510. if [ "x$1" = "xlibc-2.1.2.so" ] ; then
  511. echo "`find-file $src_path ld-2.1.2.so` -lgcc -Wl,--version-script=`find-file $src_path libc_pic.map`"
  512. return 0
  513. fi
  514. if [ "x$1" = "xlibm-2.1.2.so" -o "x$1" = "xlibm-2.1.3.so" ] ; then
  515. echo "-Wl,--version-script=`find-file $src_path libm_pic.map`"
  516. return 0
  517. fi
  518. if [ "x$1" = "xlibc-2.1.3.so" ] ; then
  519. echo "`find-file $src_path ld-2.1.3.so` -lgcc -Wl,--version-script=`find-file $src_path libc_pic.map`"
  520. return 0
  521. fi
  522. if [ "x$1" = "xlibc-2.2.so" ] ; then
  523. echo "`find-file $src_path ld-2.2.so` -lgcc -Wl,--version-script=`find-file $src_path libc_pic.map`"
  524. return 0
  525. fi
  526. if [ "x$1" = "xlibc-2.2.1.so" ] ; then
  527. echo "`find-file $src_path ld-2.2.1.so` -lgcc -Wl,--version-script=`find-file $src_path libc_pic.map`"
  528. return 0
  529. fi
  530. if [ "x$1" = "xlibc-2.2.2.so" ] ; then
  531. echo "`find-file $src_path ld-2.2.2.so` -lgcc -Wl,--version-script=`find-file $src_path libc_pic.map`"
  532. return 0
  533. fi
  534. return 0
  535. }
  536. # install-small-lib LIB_SONAME
  537. # makes a small version of library LIB_SONAME
  538. #
  539. # This happens the following way:
  540. # 0. Make exception for the linker ld.
  541. # 1. Try to figure out complete path of pic library.
  542. # 2. If no found, copy the shared library, else:
  543. # a. Get shared libraries this lib depends on, transform into a
  544. # list of "-lfoo" options.
  545. # b. Get a list of symbols both provided by the lib and in the undefined
  546. # symbols list.
  547. # c. Make the library, strip it.
  548. # d. Add symbols that are still undefined to the undefined symbols list.
  549. # e. Put library into place.
  550. install-small-lib () {
  551. if [ $# != 1 ] ; then
  552. echo 1>&2 $0: install-small-lib: internal error: called with invalid number of arguments
  553. exit 1
  554. fi
  555. local src_file=`find-file $src_path $1`
  556. if `echo "$1" | grep -q ^ld` ; then
  557. get-provided-symbols "$src_file" >> $fl_dir/provided-symbols
  558. $action $objcopy --strip-unneeded -R .note -R .comment "$src_file" "$dest/$1"
  559. return 0
  560. fi
  561. local pic_objects=`get-pic-file "$1"`
  562. local extra_flags=`get-extra-flags "$1"`
  563. local architecture=`dpkg --print-architecture`
  564. # some arm bins or libs are improperly linked, force -lgcc
  565. if [ "$architecture" = arm ]; then
  566. extra_flags="$extra_flags -lgcc"
  567. fi
  568. if [ "x$pic_objects" = x ] ; then
  569. $verbose 2>&1 No pic archive for library "$1" found, falling back to simple copy.
  570. get-provided-symbols-of-so-lib "$src_file" >> $fl_dir/provided-symbols
  571. get-undefined-symbols "$src_file" >> $fl_dir/undefined-symbols
  572. $action $objcopy --strip-unneeded -R .note -R .comment "$src_file" "$dest/$1"
  573. else
  574. $verbose 2>&1 Make small lib from "$pic_objects" in "$dest/$1".
  575. # XXX: If ld is NEEDED, we need to include it on the gcc command line
  576. get-library-depends "$src_file" \
  577. | sed -n -e 's/^lib\(.*\)\.so.*$/\1/p' > $fl_dir/lib-dependencies
  578. get-provided-symbols $pic_objects > $fl_dir/lib-provided-symbols
  579. # Argument order does matter:
  580. get-common-symbols $fl_dir/lib-provided-symbols \
  581. $fl_dir/undefined-symbols > $fl_dir/lib-symbols-to-include
  582. ${gcc} \
  583. -nostdlib -nostartfiles -shared \
  584. "-Wl,-soname=$1" \
  585. `cat $fl_dir/lib-symbols-to-include | sed 's/^/-u/'` \
  586. -o $fl_dir/lib-so \
  587. $pic_objects $extra_flags \
  588. "-L$dest" \
  589. -L`echo $src_path | sed -e 's/::*/:/g' -e 's/^://' -e 's/:$//' \
  590. -e 's/:/ -L/g'` \
  591. `cat $fl_dir/lib-dependencies | sed 's/^/-l/'` \
  592. && $objcopy --strip-unneeded -R .note -R .comment $fl_dir/lib-so $fl_dir/lib-so-stripped \
  593. || {
  594. echo 1>&2 $0: install-small-lib: $gcc or $objcopy failed.
  595. exit 1
  596. }
  597. get-undefined-symbols $fl_dir/lib-so-stripped \
  598. >> $fl_dir/undefined-symbols
  599. get-provided-symbols-of-so-lib $fl_dir/lib-so-stripped >> $fl_dir/provided-symbols
  600. $action cp $fl_dir/lib-so-stripped "$dest/$1"
  601. fi
  602. }
  603. # install-libs-in-sphere [LIB1,...]
  604. # extracts the libs in a shrinked node and cycles through them until all
  605. # possible symbols are resolved.
  606. # Always make sure this can be called recursively (from install-libs)!
  607. install-libs-in-sphere () {
  608. if [ $# != 1 ] ; then
  609. echo 1>&2 $0: install-libs-in-sphere: internal error: called with invalid number of arguments
  610. exit 1
  611. fi
  612. # Unfortunately, we need a small parser here to do the right thing when
  613. # spheres are within spheres etc. RegEx simply can't count brackets. :(
  614. local string=`echo "$1" | sed -e 's/^\[//' -e 's/\]$//'`
  615. local char
  616. local result=
  617. local depth=0
  618. while [ "x$string" != x ] ; do
  619. # Jump to next special char for faster operation.
  620. # Don't be confused by the regex, it matches everything but ],[
  621. char=`echo $string | sed -e 's/^\([^],[]*\).*$/\1/'`
  622. string=`echo $string | sed -e 's/^[^],[]*//'`
  623. result="$result$char";
  624. # Read special char
  625. char=`echo $string | sed -e 's/^\(.\).*$/\1/'`
  626. string=`echo $string | sed -e 's/^.//'`
  627. case "$char" in
  628. [) depth=$(($depth+1));;
  629. ]) depth=$(($depth-1));;
  630. ,) if [ $depth = 0 ] ; then
  631. char=' ';
  632. fi;;
  633. esac
  634. result="$result$char";
  635. done
  636. $verbose 2>&1 "RESOLVING LOOP...`echo $result | md5sum`"
  637. echo XXX: CODE NOT FINISHED
  638. install-libs $result
  639. $verbose 2>&1 "END OF LOOP... `echo $result | md5sum`"
  640. }
  641. # install-libs LIB1 ...
  642. # goes through an ordered list of libraries and installs them.
  643. # Make sure this can be called recursively, or hell breaks loose.
  644. # Note that the code is (almost) tail-recursive. I wish I could
  645. # write this in Scheme ;)
  646. install-libs () {
  647. local cur_lib
  648. local lib
  649. for cur_lib in "$@" ; do
  650. if echo "$cur_lib" | grep -q '^\[' ; then
  651. install-libs-in-sphere "$cur_lib"
  652. else
  653. lib=`find-file $src_path $cur_lib`
  654. if [ -L "$lib" ] ; then
  655. lib=`basename \`readlink $lib\``
  656. create-link $lib $dest/$cur_lib
  657. else
  658. install-small-lib $cur_lib
  659. fi
  660. fi
  661. done
  662. }
  663. #
  664. # MAIN PROGRAM
  665. #
  666. # 1. Option Processing
  667. # 2. Data Initialization
  668. # 3. Graph Construction and Reduction
  669. # 4. Library Installation
  670. # Global Files:
  671. # $fl_dir/undefined-symbols
  672. # Holds all undefined symbols we consider for inclusion.
  673. # Only grows. Does not to be sort'ed and uniq'ed, but will
  674. # get occasionally.
  675. # $fl_dir/provided-symbols
  676. # Holds all defined symbols we included.
  677. # Only grows. Should later be a superset of undefined-symbols.
  678. # But some weak symbols may be missing!
  679. # $fl_dir/library-depends
  680. # Queue of all libraries to consider.
  681. #
  682. # 1. Option Processing
  683. #
  684. while :; do
  685. case "$1" in
  686. -L) src_path="$src_path:$2"; shift 2;;
  687. -d|--dest-dir) dest=$2; shift 2;;
  688. -n|--dry-run) action="echo"; shift;;
  689. -v|--verbose) verbose="echo"; shift;;
  690. -V|--version) echo "$version"; exit 1;;
  691. -h|--help)
  692. echo "$usage"
  693. echo "Make a set of minimal libraries for FILE ... in directory DEST."
  694. echo ''
  695. echo "\
  696. Options:
  697. -L DIRECTORY Add DIRECTORY to library search path.
  698. -n, --dry-run Don't actually run any commands; just print them.
  699. -v, --verbose Print additional progress information.
  700. -V, --version Print the version number and exit.
  701. -h, --help Print this help and exit.
  702. -d, --dest-dir DIRECTORY Create libraries in DIRECTORY.
  703. Required arguments for long options are also mandatory for the short options."
  704. exit 0;;
  705. -*) echo 1>&2 $0: $1: unknown flag; echo 1>&2 "$usage"; echo 1>&2 "$try"; exit 1;;
  706. ?*) exec="$exec $1"; shift;;
  707. *) break;;
  708. esac
  709. done
  710. src_path=${src_path-$default_src_path}
  711. if [ "x$exec" = x ] ; then
  712. exit 0
  713. fi
  714. if [ "x$dest" = x ] ; then
  715. echo 1>&2 $0: no destination directory given; echo 1>&2 "$usage"; exit 1
  716. fi
  717. #
  718. # 2. Data Initialization
  719. #
  720. $verbose -n 2>&1 "Initializing data objects... "
  721. # Temporary directory.
  722. fl_dir="/tmp/,mklibs.$$"
  723. set -e
  724. mkdir $fl_dir
  725. set +e
  726. trap "rm -fr $fl_dir" EXIT
  727. # Intialize our symbol array and library queue with the information
  728. # from the executables.
  729. get-undefined-symbols $exec > $fl_dir/undefined-symbols
  730. add-to-queue-if-not-there $fl_dir/library-depends `get-library-depends $exec`
  731. $verbose 2>&1 "done."
  732. #
  733. # 3.a Graph Construction
  734. #
  735. # Build the dependency graph, add new library dependencies to the queue on
  736. # the way.
  737. # If the soname is a link, add the target to the end of the queue and
  738. # add a simple arrow to the graph.
  739. # If the soname is a real lib, get its dependencies and add them to
  740. # the queue. Furthermore, add arrows to the graph. If the lib is not
  741. # dependant on any other lib, add the node to make sure it is mentioned
  742. # at least once in the graph.
  743. $verbose -n 2>&1 "Constructing dependency graph... ("
  744. while cur_lib=`get-top-of-queue $fl_dir/library-depends`
  745. do
  746. lib=`find-file $src_path $cur_lib`
  747. if [ -L "$lib" ] ; then
  748. $verbose -n 2>&1 L
  749. lib=`basename \`readlink $lib\``
  750. add-to-queue-if-not-there $fl_dir/library-depends "$lib"
  751. add-arrow $fl_dir/dependency-graph "$cur_lib" "$lib"
  752. else
  753. get-library-depends "$lib" > $fl_dir/backup
  754. if [ "x`head -n 1 $fl_dir/backup`" = x ] ; then
  755. $verbose -n 2>&1 N
  756. add-node $fl_dir/dependency-graph "$cur_lib"
  757. else
  758. $verbose -n 2>&1 A
  759. for lib in `cat $fl_dir/backup` ; do
  760. add-to-queue-if-not-there $fl_dir/library-depends "$lib"
  761. add-arrow $fl_dir/dependency-graph "$cur_lib" "$lib"
  762. done
  763. fi
  764. fi
  765. done
  766. $verbose 2>&1 ") done."
  767. #
  768. # 3.b Graph Reduction
  769. #
  770. # Find and shrink cycles in the graph.
  771. $verbose -n 2>&1 "Eliminating cycles... ("
  772. while cycle=`find-cycle "$fl_dir/dependency-graph"` ; do
  773. $verbose -n 2>&1 C
  774. shrink-nodes "$fl_dir/dependency-graph" $cycle
  775. done
  776. $verbose 2>&1 ") done."
  777. #
  778. # 4. Library Installation
  779. #
  780. # Let tsort(1) do the actual work on the cycle-free graph.
  781. tsort $fl_dir/dependency-graph > $fl_dir/backup
  782. # Now the ordered list of libraries (or cycles of them)
  783. # can be processed by install-libs. This is indeed the last step.
  784. install-libs `cat $fl_dir/backup`
  785. #sort -u $fl_dir/provided-symbols > $fl_dir/diag1
  786. #sort -u $fl_dir/undefined-symbols > $fl_dir/diag2
  787. #cat $fl_dir/diag1 $fl_dir/diag2 | sort | uniq -u > $fl_dir/diag3
  788. ## diag3 has now the symmetric difference.
  789. #cat $fl_dir/diag3 $fl_dir/diag2 | sort | uniq -d > $fl_dir/diag1
  790. ## diag1 has now all undefined symbols that are not provided.
  791. ##cat $fl_dir/diag1 | wc
  792. ## Note that some of these symbols are weak and not having them is probably
  793. ## not an error.
  794. exit 0