mklibs.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. #! /usr/bin/python
  2. # mklibs.py: An automated way to create a minimal /lib/ directory.
  3. #
  4. # Copyright 2001 by Falk Hueffner <falk@debian.org>
  5. # & Goswin Brederlow <goswin.brederlow@student.uni-tuebingen.de>
  6. #
  7. # mklibs.sh by Marcus Brinkmann <Marcus.Brinkmann@ruhr-uni-bochum.de>
  8. # used as template
  9. #
  10. # This program is free software; you can redistribute it and/or modify
  11. # it under the terms of the GNU General Public License as published by
  12. # the Free Software Foundation; either version 2 of the License, or
  13. # (at your option) any later version.
  14. #
  15. # This program is distributed in the hope that it will be useful,
  16. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. # GNU General Public License for more details.
  19. #
  20. # You should have received a copy of the GNU General Public License
  21. # along with this program; if not, write to the Free Software
  22. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. # HOW IT WORKS
  24. #
  25. # - Gather all unresolved symbols and libraries needed by the programs
  26. # and reduced libraries
  27. # - Gather all symbols provided by the already reduced libraries
  28. # (none on the first pass)
  29. # - If all symbols are provided we are done
  30. # - go through all libraries and remember what symbols they provide
  31. # - go through all unresolved/needed symbols and mark them as used
  32. # - for each library:
  33. # - find pic file (if not present copy and strip the so)
  34. # - compile in only used symbols
  35. # - strip
  36. # - back to the top
  37. # TODO
  38. # * complete argument parsing as given as comment in main
  39. import commands
  40. import string
  41. import re
  42. import sys
  43. import os
  44. import glob
  45. import getopt
  46. from stat import *
  47. DEBUG_NORMAL = 1
  48. DEBUG_VERBOSE = 2
  49. DEBUG_SPAM = 3
  50. debuglevel = DEBUG_NORMAL
  51. def debug(level, *msg):
  52. if debuglevel >= level:
  53. print string.join(msg)
  54. # A simple set class. It should be replaced with the standard sets.Set
  55. # type as soon as Python 2.3 is out.
  56. class Set:
  57. def __init__(self):
  58. self.__dict = {}
  59. def add(self, obj):
  60. self.__dict[obj] = 1
  61. def contains(self, obj):
  62. return self.__dict.has_key(obj)
  63. def merge(self, s):
  64. for e in s.elems():
  65. self.add(e)
  66. def elems(self):
  67. return self.__dict.keys()
  68. def size(self):
  69. return len(self.__dict)
  70. def __eq__(self, other):
  71. return self.__dict == other.__dict
  72. def __str__(self):
  73. return `self.__dict.keys()`
  74. def __repr__(self):
  75. return `self.__dict.keys()`
  76. # return a list of lines of output of the command
  77. def command(command, *args):
  78. debug(DEBUG_SPAM, "calling", command, string.join(args))
  79. (status, output) = commands.getstatusoutput(command + ' ' + string.join(args))
  80. if os.WEXITSTATUS(status) != 0:
  81. print "Command failed with status", os.WEXITSTATUS(status), ":", \
  82. command, string.join(args)
  83. print "With output:", output
  84. sys.exit(1)
  85. return string.split(output, '\n')
  86. # Filter a list according to a regexp containing a () group. Return
  87. # a Set.
  88. def regexpfilter(list, regexp, groupnr = 1):
  89. pattern = re.compile(regexp)
  90. result = Set()
  91. for x in list:
  92. match = pattern.match(x)
  93. if match:
  94. result.add(match.group(groupnr))
  95. return result
  96. # Return a Set of rpath strings for the passed object
  97. def rpath(obj):
  98. if not os.access(obj, os.F_OK):
  99. raise "Cannot find lib: " + obj
  100. output = command(target + "objdump", "--private-headers", obj)
  101. return map(lambda x: root + "/" + x, regexpfilter(output, ".*RPATH\s*(\S+)$").elems())
  102. # Return a Set of libraries the passed objects depend on.
  103. def library_depends(obj):
  104. if not os.access(obj, os.F_OK):
  105. raise "Cannot find lib: " + obj
  106. output = command(target + "objdump", "--private-headers", obj)
  107. return regexpfilter(output, ".*NEEDED\s*(\S+)$")
  108. # Return a list of libraries the passed objects depend on. The
  109. # libraries are in "-lfoo" format suitable for passing to gcc.
  110. def library_depends_gcc_libnames(obj):
  111. if not os.access(obj, os.F_OK):
  112. raise "Cannot find lib: " + obj
  113. output = command(target + "objdump", "--private-headers", obj)
  114. output = regexpfilter(output, ".*NEEDED\s*lib(\S+)\.so.*$")
  115. if not output.elems():
  116. return ""
  117. else:
  118. return "-l" + string.join(output.elems(), " -l")
  119. # Scan readelf output. Example:
  120. # Num: Value Size Type Bind Vis Ndx Name
  121. # 1: 000000012002ab48 168 FUNC GLOBAL DEFAULT UND strchr@GLIBC_2.0 (2)
  122. symline_regexp = \
  123. re.compile("\s*\d+: .+\s+\d+\s+\w+\s+(\w+)+\s+\w+\s+(\w+)\s+([^\s@]+)")
  124. # Return undefined symbols in an object as a Set of tuples (name, weakness)
  125. def undefined_symbols(obj):
  126. if not os.access(obj, os.F_OK):
  127. raise "Cannot find lib" + obj
  128. result = Set()
  129. output = command(target + "readelf", "-s", "-W", obj)
  130. for line in output:
  131. match = symline_regexp.match(line)
  132. if match:
  133. bind, ndx, name = match.groups()
  134. if ndx == "UND":
  135. result.add((name, bind == "WEAK"))
  136. return result
  137. # Return a Set of symbols provided by a library
  138. def provided_symbols(obj):
  139. if not os.access(obj, os.F_OK):
  140. raise "Cannot find lib" + obj
  141. result = Set()
  142. debug(DEBUG_SPAM, "provided_symbols result = ", `result`)
  143. output = command(target + "readelf", "-s", "-W", obj)
  144. for line in output:
  145. match = symline_regexp.match(line)
  146. if match:
  147. bind, ndx, name = match.groups()
  148. if bind != "LOCAL" and not ndx in ("UND", "ABS"):
  149. debug(DEBUG_SPAM, "provided_symbols adding ", `name`)
  150. result.add(name)
  151. return result
  152. # Return real target of a symlink
  153. def resolve_link(file):
  154. debug(DEBUG_SPAM, "resolving", file)
  155. while S_ISLNK(os.lstat(file)[ST_MODE]):
  156. new_file = os.readlink(file)
  157. if new_file[0] != "/":
  158. file = os.path.join(os.path.dirname(file), new_file)
  159. else:
  160. file = new_file
  161. debug(DEBUG_SPAM, "resolved to", file)
  162. return file
  163. # Find complete path of a library, by searching in lib_path
  164. def find_lib(lib):
  165. for path in lib_path:
  166. if os.access(path + "/" + lib, os.F_OK):
  167. return path + "/" + lib
  168. return ""
  169. # Find a PIC archive for the library
  170. def find_pic(lib):
  171. base_name = so_pattern.match(lib).group(1)
  172. for path in lib_path:
  173. for file in glob.glob(path + "/" + base_name + "_pic.a"):
  174. if os.access(file, os.F_OK):
  175. return resolve_link(file)
  176. return ""
  177. # Find a PIC .map file for the library
  178. def find_pic_map(lib):
  179. base_name = so_pattern.match(lib).group(1)
  180. for path in lib_path:
  181. for file in glob.glob(path + "/" + base_name + "_pic.map"):
  182. if os.access(file, os.F_OK):
  183. return resolve_link(file)
  184. return ""
  185. def extract_soname(so_file):
  186. soname_data = regexpfilter(command(target + "readelf", "--all", "-W", so_file),
  187. ".*SONAME.*\[(.*)\].*")
  188. if soname_data.elems():
  189. return soname_data.elems()[0]
  190. return ""
  191. def usage(was_err):
  192. if was_err:
  193. outfd = sys.stderr
  194. else:
  195. outfd = sys.stdout
  196. print >> outfd, "Usage: mklibs [OPTION]... -d DEST FILE ..."
  197. print >> outfd, "Make a set of minimal libraries for FILE(s) in DEST."
  198. print >> outfd, ""
  199. print >> outfd, " -d, --dest-dir DIRECTORY create libraries in DIRECTORY"
  200. print >> outfd, " -D, --no-default-lib omit default libpath (", string.join(default_lib_path, " : "), ")"
  201. print >> outfd, " -L DIRECTORY[:DIRECTORY]... add DIRECTORY(s) to the library search path"
  202. print >> outfd, " --ldlib LDLIB use LDLIB for the dynamic linker"
  203. print >> outfd, " --libc-extras-dir DIRECTORY look for libc extra files in DIRECTORY"
  204. # Ugh... Adding the trailing '-' breaks common practice.
  205. #print >> outfd, " --target TARGET prepend TARGET- to the gcc and binutils calls"
  206. print >> outfd, " --target TARGET prepend TARGET to the gcc and binutils calls"
  207. print >> outfd, " --root ROOT search in ROOT for library rpaths"
  208. print >> outfd, " -v, --verbose explain what is being done"
  209. print >> outfd, " -h, --help display this help and exit"
  210. sys.exit(was_err)
  211. def version(vers):
  212. print "mklibs: version ",vers
  213. print ""
  214. #################### main ####################
  215. ## Usage: ./mklibs.py [OPTION]... -d DEST FILE ...
  216. ## Make a set of minimal libraries for FILE ... in directory DEST.
  217. ##
  218. ## Options:
  219. ## -L DIRECTORY Add DIRECTORY to library search path.
  220. ## -D, --no-default-lib Do not use default lib directories of /lib:/usr/lib
  221. ## -n, --dry-run Don't actually run any commands; just print them.
  222. ## -v, --verbose Print additional progress information.
  223. ## -V, --version Print the version number and exit.
  224. ## -h, --help Print this help and exit.
  225. ## --ldlib Name of dynamic linker (overwrites environment variable ldlib)
  226. ## --libc-extras-dir Directory for libc extra files
  227. ## --target Use as prefix for gcc or binutils calls
  228. ##
  229. ## -d, --dest-dir DIRECTORY Create libraries in DIRECTORY.
  230. ##
  231. ## Required arguments for long options are also mandatory for the short options.
  232. # Clean the environment
  233. vers="0.12 with uClibc fixes"
  234. os.environ['LC_ALL'] = "C"
  235. # Argument parsing
  236. opts = "L:DnvVhd:r:"
  237. longopts = ["no-default-lib", "dry-run", "verbose", "version", "help",
  238. "dest-dir=", "ldlib=", "libc-extras-dir=", "target=", "root="]
  239. # some global variables
  240. lib_rpath = []
  241. lib_path = []
  242. dest_path = "DEST"
  243. ldlib = "LDLIB"
  244. include_default_lib_path = "yes"
  245. default_lib_path = ["/lib/", "/usr/lib/", "/usr/X11R6/lib/"]
  246. libc_extras_dir = "/usr/lib/libc_pic"
  247. target = ""
  248. root = ""
  249. so_pattern = re.compile("((lib|ld).*)\.so(\..+)*")
  250. script_pattern = re.compile("^#!\s*/")
  251. try:
  252. optlist, proglist = getopt.getopt(sys.argv[1:], opts, longopts)
  253. except getopt.GetoptError, msg:
  254. print >> sys.stderr, msg
  255. usage(1)
  256. for opt, arg in optlist:
  257. if opt in ("-v", "--verbose"):
  258. if debuglevel < DEBUG_SPAM:
  259. debuglevel = debuglevel + 1
  260. elif opt == "-L":
  261. lib_path.extend(string.split(arg, ":"))
  262. elif opt in ("-d", "--dest-dir"):
  263. dest_path = arg
  264. elif opt in ("-D", "--no-default-lib"):
  265. include_default_lib_path = "no"
  266. elif opt == "--ldlib":
  267. ldlib = arg
  268. elif opt == "--libc-extras-dir":
  269. libc_extras_dir = arg
  270. elif opt == "--target":
  271. #target = arg + "-"
  272. target = arg
  273. elif opt in ("-r", "--root"):
  274. root = arg
  275. elif opt in ("--help", "-h"):
  276. usage(0)
  277. sys.exit(0)
  278. elif opt in ("--version", "-V"):
  279. version(vers)
  280. sys.exit(0)
  281. else:
  282. print "WARNING: unknown option: " + opt + "\targ: " + arg
  283. if include_default_lib_path == "yes":
  284. lib_path.extend(default_lib_path)
  285. if ldlib == "LDLIB":
  286. ldlib = os.getenv("ldlib")
  287. objects = {} # map from inode to filename
  288. for prog in proglist:
  289. inode = os.stat(prog)[ST_INO]
  290. if objects.has_key(inode):
  291. debug(DEBUG_SPAM, prog, "is a hardlink to", objects[inode])
  292. elif so_pattern.match(prog):
  293. debug(DEBUG_SPAM, prog, "is a library")
  294. elif script_pattern.match(open(prog).read(256)):
  295. debug(DEBUG_SPAM, prog, "is a script")
  296. else:
  297. objects[inode] = prog
  298. if not ldlib:
  299. pattern = re.compile(".*Requesting program interpreter:.*/([^\]/]+).*")
  300. for obj in objects.values():
  301. output = command(target + "readelf", "--program-headers", obj)
  302. for x in output:
  303. match = pattern.match(x)
  304. if match:
  305. ldlib = match.group(1)
  306. break
  307. if ldlib:
  308. break
  309. if not ldlib:
  310. sys.exit("E: Dynamic linker not found, aborting.")
  311. debug(DEBUG_NORMAL, "I: Using", ldlib, "as dynamic linker.")
  312. pattern = re.compile(".*ld-uClibc.*");
  313. if pattern.match(ldlib):
  314. uclibc = 1
  315. else:
  316. uclibc = 0
  317. # Check for rpaths
  318. for obj in objects.values():
  319. rpath_val = rpath(obj)
  320. if rpath_val:
  321. if root:
  322. if debuglevel >= DEBUG_VERBOSE:
  323. print "Adding rpath " + string.join(rpath_val, ":") + " for " + obj
  324. lib_rpath.extend(rpath_val)
  325. else:
  326. print "warning: " + obj + " may need rpath, but --root not specified"
  327. lib_path.extend(lib_rpath)
  328. passnr = 1
  329. previous_pass_unresolved = Set()
  330. while 1:
  331. debug(DEBUG_NORMAL, "I: library reduction pass", `passnr`)
  332. if debuglevel >= DEBUG_VERBOSE:
  333. print "Objects:",
  334. for obj in objects.values():
  335. print obj[string.rfind(obj, '/') + 1:],
  336. print
  337. passnr = passnr + 1
  338. # Gather all already reduced libraries and treat them as objects as well
  339. small_libs = []
  340. for lib in regexpfilter(os.listdir(dest_path), "(.*-so-stripped)$").elems():
  341. obj = dest_path + "/" + lib
  342. small_libs.append(obj)
  343. inode = os.stat(obj)[ST_INO]
  344. if objects.has_key(inode):
  345. debug(DEBUG_SPAM, obj, "is hardlink to", objects[inode])
  346. else:
  347. objects[inode] = obj
  348. # DEBUG
  349. for obj in objects.values():
  350. small_libs.append(obj)
  351. debug(DEBUG_VERBOSE, "Object:", obj)
  352. # calculate what symbols and libraries are needed
  353. needed_symbols = Set() # Set of (name, weakness-flag)
  354. libraries = Set()
  355. for obj in objects.values():
  356. needed_symbols.merge(undefined_symbols(obj))
  357. libraries.merge(library_depends(obj))
  358. # FIXME: on i386 this is undefined but not marked UND
  359. # I don't know how to detect those symbols but this seems
  360. # to be the only one and including it on alpha as well
  361. # doesn't hurt. I guess all archs can live with this.
  362. needed_symbols.add(("sys_siglist", 1))
  363. # calculate what symbols are present in small_libs
  364. present_symbols = Set()
  365. for lib in small_libs:
  366. present_symbols.merge(provided_symbols(lib))
  367. # are we finished?
  368. using_ctor_dtor = 0
  369. num_unresolved = 0
  370. present_symbols_elems = present_symbols.elems()
  371. unresolved = Set()
  372. for (symbol, is_weak) in needed_symbols.elems():
  373. if not symbol in present_symbols_elems:
  374. debug(DEBUG_SPAM, "Still need:", symbol, `is_weak`)
  375. unresolved.add((symbol, is_weak))
  376. num_unresolved = num_unresolved + 1
  377. debug (DEBUG_NORMAL, `needed_symbols.size()`, "symbols,",
  378. `num_unresolved`, "unresolved")
  379. if num_unresolved == 0:
  380. break
  381. if unresolved == previous_pass_unresolved:
  382. # No progress in last pass. Verify all remaining symbols are weak.
  383. for (symbol, is_weak) in unresolved.elems():
  384. if not is_weak:
  385. raise "Unresolvable symbol " + symbol
  386. break
  387. previous_pass_unresolved = unresolved
  388. library_symbols = {}
  389. library_symbols_used = {}
  390. symbol_provider = {}
  391. # Calculate all symbols each library provides
  392. for library in libraries.elems():
  393. path = find_lib(library)
  394. if not path:
  395. sys.exit("Library not found: " + library + " in path: "
  396. + string.join(lib_path, " : "))
  397. symbols = provided_symbols(path)
  398. library_symbols[library] = Set()
  399. library_symbols_used[library] = Set()
  400. for symbol in symbols.elems():
  401. if symbol_provider.has_key(symbol):
  402. # in doubt, prefer symbols from libc
  403. if re.match("^libc[\.-]", library):
  404. library_symbols[library].add(symbol)
  405. symbol_provider[symbol] = library
  406. else:
  407. debug(DEBUG_SPAM, "duplicate symbol", symbol, "in",
  408. symbol_provider[symbol], "and", library)
  409. else:
  410. library_symbols[library].add(symbol)
  411. symbol_provider[symbol] = library
  412. # Fixup support for constructors and destructors
  413. if symbol_provider.has_key("_init"):
  414. debug(DEBUG_VERBOSE, library, ": Library has a constructor!");
  415. using_ctor_dtor = 1
  416. library_symbols[library].add("_init")
  417. symbol_provider["_init"] = library
  418. library_symbols_used[library].add("_init")
  419. if symbol_provider.has_key("_fini"):
  420. debug(DEBUG_VERBOSE, library, ": Library has a destructor!");
  421. using_ctor_dtor = 1
  422. library_symbols[library].add("_fini")
  423. symbol_provider["_fini"] = library
  424. library_symbols_used[library].add("_fini")
  425. # which symbols are actually used from each lib
  426. for (symbol, is_weak) in needed_symbols.elems():
  427. if not symbol_provider.has_key(symbol):
  428. if not is_weak:
  429. if not uclibc or (symbol != "main"):
  430. raise "No library provides non-weak " + symbol
  431. else:
  432. lib = symbol_provider[symbol]
  433. library_symbols_used[lib].add(symbol)
  434. # reduce libraries
  435. for library in libraries.elems():
  436. debug(DEBUG_VERBOSE, "reducing", library)
  437. debug(DEBUG_SPAM, "using: " + string.join(library_symbols_used[library].elems()))
  438. so_file = find_lib(library)
  439. if root and (re.compile("^" + root).search(so_file)):
  440. debug(DEBUG_VERBOSE, "no action required for " + so_file)
  441. continue
  442. so_file_name = os.path.basename(so_file)
  443. if not so_file:
  444. sys.exit("File not found:" + library)
  445. pic_file = find_pic(library)
  446. if not pic_file:
  447. # No pic file, so we have to use the .so file, no reduction
  448. debug(DEBUG_VERBOSE, "No pic file found for", so_file, "; copying")
  449. command(target + "objcopy", "--strip-unneeded -R .note -R .comment",
  450. so_file, dest_path + "/" + so_file_name + "-so-stripped")
  451. else:
  452. # we have a pic file, recompile
  453. debug(DEBUG_SPAM, "extracting from:", pic_file, "so_file:", so_file)
  454. soname = extract_soname(so_file)
  455. if soname == "":
  456. debug(DEBUG_VERBOSE, so_file, " has no soname, copying")
  457. continue
  458. debug(DEBUG_SPAM, "soname:", soname)
  459. base_name = so_pattern.match(library).group(1)
  460. # libc needs its soinit.o and sofini.o as well as the pic
  461. if (base_name == "libc") and not uclibc:
  462. # force dso_handle.os to be included, otherwise reduced libc
  463. # may segfault in ptmalloc_init due to undefined weak reference
  464. extra_flags = find_lib(ldlib) + " -u __dso_handle"
  465. extra_pre_obj = libc_extras_dir + "/soinit.o"
  466. extra_post_obj = libc_extras_dir + "/sofini.o"
  467. else:
  468. extra_flags = ""
  469. extra_pre_obj = ""
  470. extra_post_obj = ""
  471. map_file = find_pic_map(library)
  472. if map_file:
  473. extra_flags = extra_flags + " -Wl,--version-script=" + map_file
  474. if library_symbols_used[library].elems():
  475. joined_symbols = "-u" + string.join(library_symbols_used[library].elems(), " -u")
  476. else:
  477. joined_symbols = ""
  478. if using_ctor_dtor == 1:
  479. extra_flags = extra_flags + " -shared"
  480. # compile in only used symbols
  481. command(target + "gcc",
  482. "-nostdlib -nostartfiles -shared -Wl,-soname=" + soname,\
  483. joined_symbols, \
  484. "-o", dest_path + "/" + so_file_name + "-so", \
  485. extra_pre_obj, \
  486. pic_file, \
  487. extra_post_obj, \
  488. extra_flags, \
  489. "-lgcc -L", dest_path, \
  490. "-L" + string.join(lib_path, " -L"), \
  491. library_depends_gcc_libnames(so_file))
  492. # strip result
  493. command(target + "objcopy", "--strip-unneeded -R .note -R .comment",
  494. dest_path + "/" + so_file_name + "-so",
  495. dest_path + "/" + so_file_name + "-so-stripped")
  496. ## DEBUG
  497. debug(DEBUG_VERBOSE, so_file, "\t", `os.stat(so_file)[ST_SIZE]`)
  498. debug(DEBUG_VERBOSE, dest_path + "/" + so_file_name + "-so", "\t",
  499. `os.stat(dest_path + "/" + so_file_name + "-so")[ST_SIZE]`)
  500. debug(DEBUG_VERBOSE, dest_path + "/" + so_file_name + "-so-stripped",
  501. "\t", `os.stat(dest_path + "/" + so_file_name + "-so-stripped")[ST_SIZE]`)
  502. # Finalising libs and cleaning up
  503. for lib in regexpfilter(os.listdir(dest_path), "(.*)-so-stripped$").elems():
  504. os.rename(dest_path + "/" + lib + "-so-stripped", dest_path + "/" + lib)
  505. for lib in regexpfilter(os.listdir(dest_path), "(.*-so)$").elems():
  506. os.remove(dest_path + "/" + lib)
  507. # Canonicalize library names.
  508. for lib in regexpfilter(os.listdir(dest_path), "(.*so[.\d]*)$").elems():
  509. this_lib_path = dest_path + "/" + lib
  510. if os.path.islink(this_lib_path):
  511. debug(DEBUG_VERBOSE, "Unlinking %s." % lib)
  512. os.remove(this_lib_path)
  513. continue
  514. soname = extract_soname(this_lib_path)
  515. if soname:
  516. debug(DEBUG_VERBOSE, "Moving %s to %s." % (lib, soname))
  517. os.rename(dest_path + "/" + lib, dest_path + "/" + soname)
  518. # Make sure the dynamic linker is present and is executable
  519. ld_file = find_lib(ldlib)
  520. ld_file_name = os.path.basename(ld_file)
  521. if not os.access(dest_path + "/" + ld_file_name, os.F_OK):
  522. debug(DEBUG_NORMAL, "I: stripping and copying dynamic linker.")
  523. command(target + "objcopy", "--strip-unneeded -R .note -R .comment",
  524. ld_file, dest_path + "/" + ld_file_name)
  525. os.chmod(dest_path + "/" + ld_file_name, 0755)