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