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
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
32 # This utilitiy helps to reduce the necessary libraries to only include the
33 # symbols needed to run a given set of executables.
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.
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
52 # The reasons I chose shell are:
53 # * Shell scripts are very portable and available even on minimal systems as
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.
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.
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 !!!
84 # 1999-09-13 Marcus Brinkmann <brinkmd@debian.org>
86 # * Initial release (v0.1).
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"
98 default_src_path=/lib:/usr/lib
105 objdump=${OBJDUMP-objdump}
106 objcopy=${OBJCOPY-objcopy}
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.
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\"
134 # provides a very simple type assertion
135 # Turns FILE into a graph if it isn't already and returns 0.
139 for file in "$@" ; do
140 if [ ! -e "$file" ] ; then
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.
153 if [ $# != 2 ] ; then
154 echo 1>&2 $0: add-node: internal error: called with invalid number of arguments
162 # add-arrow FILE NODE1 NODE2
163 # add an arrow from NODE1 to NODE2 to graph FILE.
166 if [ $# != 3 ] ; then
167 echo 1>&2 $0: add-arrow: internal error: called with invalid number of arguments
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
182 if [ $# != 1 ] ; then
183 echo 1>&2 $0: find-cycle: internal error: called with invalid number of arguments
186 tsort "$1" 2> "$fl_dir/find-cycle" > /dev/null
187 if [ "x`cat $fl_dir/find-cycle
`" = x ] ; then
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
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
211 # Always shrink all cycles, or you may get unresolved symbols.
214 # N1 ---> N2 N1 -------> /------------\
215 # | "shrink-nodes N2 N4" | _ | [N2,N4] |
216 # v -------------------> v _____/| \------------/
219 # A small helper function will aid us...
220 # equal-match STRING STRING1 ...
221 # return 0 if STRING is among STRING1 ..., 1 otherwise.
227 for stringk in "$@" ; do
228 if [ "x$string" = "x$stringk" ] ; then
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
255 rnode=`echo $head|
sed 's/^[^ ]* //'`
256 if equal-match "$rnode" "$@" ; then
259 echo "$lnode $rnode" >> "$fl_dir/shrink-cycle"
261 cat "$fl_dir/shrink-cycle" | sort -u > "$graph"
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
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 () {
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\"
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.
305 for qfile in "$@" ; do
306 if [ ! -e "$qfile" ] ; then
307 echo "$QUEUE_SEPERATOR" > "$qfile"
309 if ! grep -q "^$QUEUE_SEPERATOR$" "$qfile" ; then
310 echo "$QUEUE_SEPERATOR" >> "$qfile";
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
328 local head=`head -n 1 "$1"`
329 if [ "x$head" = "x$QUEUE_SEPERATOR" ] ; then
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"
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
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
351 add-to-queue-if-not-there () {
355 check-queue-entry "$@"
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"
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 () {
382 echo 1>&2 $0: get-library-depends: internal error: no arguments
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 () {
395 echo 1>&2 $0: get-undefined-symbols: internal error: no arguments
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 () {
417 echo 1>&2 $0: get-provided-symbols: internal error: no arguments
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 () {
428 echo 1>&2 $0: get-provided-symbols: internal error: no arguments
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
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"
453 while symbol=`get-top-of-queue
$fl_dir/get-common-symbols
` ; do
454 grep ^$symbol\$\\\|^$symbol@ "$1"
458 # create-link TARGET LINK_NAME
459 # creates a soft link if there isn't one already.
462 if [ $# != 2 ] ; then
463 echo 1>&2 $0: create-link: internal error: called with invalid number of arguments
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 ':'.
477 if [ $# != 2 ] ; then
478 echo 1>&2 $0: find-file: internal error: exactly two arguments required
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
490 path=`echo $path |
sed -e 's/^[^:]*:*//'`
491 dir=`echo $path |
sed -e 's/:.*$//'`
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.
503 if [ $# -lt 2 ] ; then
504 echo 1>&2 $0: find-files: internal error: too few arguments
507 local path="$1" ; shift
508 while [ $# != 0 ] ; do
515 # returns the filename of the pic archive for LIB.
516 # Note: There doesn't seem to be any convention, *ick*.
519 if [ $# != 1 ] ; then
520 echo 1>&2 $0: get-pic-file: internal error: called with invalid number of arguments
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
`
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
`
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
`
541 if [ "x$1" = "xlibslang.so.1.3.9" ] ; then
542 echo `find-file
$src_path libslang1.3
.9_pic.a
`
545 if [ "x$1" = "xlibslang.so.1.4.1" ] ; then
546 echo `find-file
$src_path libslang1.4
.1_pic.a
`
549 local libname=`echo $1 |
sed -e 's/^lib\(.*\).so.*/\1/'`
550 echo `find-file
"$src_path" lib
${libname}_pic.a
`
555 if [ $# != 1 ] ; then
556 echo 1>&2 $0: get-extra-flags: internal error: called with invalid number of arguments
559 if [ "x$1" = "xlibc-2.0.7.so" ] ; then
560 echo `find-file
$src_path ld-2.0
.7.so
` -lgcc
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
`"
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
`"
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
`"
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
`"
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
`"
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
`"
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
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
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"
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"
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
640 -nostdlib -nostartfiles -shared \
642 `cat $fl_dir/lib-symbols-to-include |
sed 's/^/-u/'` \
644 $pic_objects $extra_flags \
646 -L`echo $src_path |
sed -e 's/::*/:/g' -e 's/^://' -e 's/:$//' \
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 \
651 echo 1>&2 $0: install-small-lib: $gcc or $objcopy failed.
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
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/\]$//'`
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";
684 char=`echo $string |
sed -e 's/^\(.\).*$/\1/'`
685 string=`echo $string |
sed -e 's/^.//'`
687 [) depth=$(($depth+1));;
688 ]) depth=$(($depth-1));;
689 ,) if [ $depth = 0 ] ; then
693 result="$result$char";
695 $verbose 2>&1 "RESOLVING LOOP...`echo $result |
md5sum`"
696 echo XXX: CODE NOT FINISHED
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 ;)
710 for cur_lib in "$@" ; do
711 if echo "$cur_lib" | grep -q '^\[' ; then
712 install-libs-in-sphere "$cur_lib"
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
719 install-small-lib $cur_lib
728 # 1. Option Processing
729 # 2. Data Initialization
730 # 3. Graph Construction and Reduction
731 # 4. Library Installation
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
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
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;;
758 echo "Make a set of minimal libraries for FILE ... in directory DEST."
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."
772 -*) echo 1>&2 $0: $1: unknown flag; echo 1>&2 "$usage"; echo 1>&2 "$try"; exit 1;;
773 ?*) exec="$exec $1"; shift;;
778 src_path=${src_path-$default_src_path}
780 if [ "x$exec" = x ] ; then
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.$$"
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
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
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"
833 get-library-depends "$lib" > $fl_dir/backup
834 if [ "x`head -n 1 $fl_dir/backup
`" = x ] ; then
836 add-node $fl_dir/dependency-graph "$cur_lib"
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"
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
858 shrink-nodes "$fl_dir/dependency-graph" $cycle
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