diff options
Diffstat (limited to 'pym/portage/util/lafilefixer.py')
-rw-r--r-- | pym/portage/util/lafilefixer.py | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/pym/portage/util/lafilefixer.py b/pym/portage/util/lafilefixer.py new file mode 100644 index 000000000..90cc43541 --- /dev/null +++ b/pym/portage/util/lafilefixer.py @@ -0,0 +1,176 @@ +# Copyright 2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +import re + +from portage import os +from portage.exception import InvalidData + +######################################################### +# This an re-implementaion of dev-util/lafilefixer-0.5. +# rewrite_lafile() takes the contents of an lafile as a string +# It then parses the dependency_libs and inherited_linker_flags +# entries. +# We insist on dependency_libs being present. inherited_linker_flags +# is optional. +# There are strict rules about the syntax imposed by libtool's libltdl. +# See 'parse_dotla_file' and 'trim' functions in libltdl/ltdl.c. +# Note that duplicated entries of dependency_libs and inherited_linker_flags +# are ignored by libtool (last one wins), but we treat it as error (like +# lafilefixer does). +# What it does: +# * Replaces all .la files with absolut paths in dependency_libs with +# corresponding -l* and -L* entries +# (/usr/lib64/libfoo.la -> -L/usr/lib64 -lfoo) +# * Moves various flags (see flag_re below) to inherited_linker_flags, +# if such an entry was present. +# * Reorders dependency_libs such that all -R* entries precede -L* entries +# and these precede all other entries. +# * Remove duplicated entries from dependency_libs +# * Takes care that no entry to inherited_linker_flags is added that is +# already there. +######################################################### + +#These regexes are used to parse the interesting entries in the la file +dep_libs_re = re.compile("dependency_libs='(?P<value>[^']*)'$") +inh_link_flags_re = re.compile("inherited_linker_flags='(?P<value>[^']*)'$") + +#regexes for replacing stuff in -L entries. +#replace 'X11R6/lib' and 'local/lib' with 'lib', no idea what's this about. +X11_local_sub = re.compile("X11R6/lib|local/lib") +#get rid of the '..' +pkgconfig_sub1 = re.compile("usr/lib[^/]*/pkgconfig/\.\./\.\.") +pkgconfig_sub2 = re.compile("(?P<usrlib>usr/lib[^/]*)/pkgconfig/\.\.") + +#detect flags that should go into inherited_linker_flags instead of dependency_libs +flag_re = re.compile("-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads") + +def _parse_lafile_contents(contents): + """ + Parses 'dependency_libs' and 'inherited_linker_flags' lines. + """ + + dep_libs = None + inh_link_flags = None + + for line in contents.split("\n"): + m = dep_libs_re.match(line) + if m: + if dep_libs is not None: + raise InvalidData("duplicated dependency_libs entry") + dep_libs = m.group("value") + continue + + m = inh_link_flags_re.match(line) + if m: + if inh_link_flags is not None: + raise InvalidData("duplicated inherited_linker_flags entry") + inh_link_flags = m.group("value") + continue + + return dep_libs, inh_link_flags + +def rewrite_lafile(contents): + """ + Given the contents of an .la file, parse and fix it. + Returns a bool, string tuple. + The bool indicates if the file needs fixing. + The string contains the fixed contents if the file needs fixing. + Raises 'InvalidData' if the .la file is invalid. + """ + #Parse the 'dependency_libs' and 'inherited_linker_flags' lines. + dep_libs, inh_link_flags = \ + _parse_lafile_contents(contents) + + if dep_libs is None: + raise InvalidData("missing or invalid dependency_libs") + + new_dep_libs = [] + new_inh_link_flags = [] + librpath = [] + libladir = [] + + if inh_link_flags is not None: + new_inh_link_flags = inh_link_flags.split() + + #Check entries in 'dependency_libs'. + for dep_libs_entry in dep_libs.split(): + if dep_libs_entry.startswith("-l"): + #-lfoo, keep it + if dep_libs_entry not in new_dep_libs: + new_dep_libs.append(dep_libs_entry) + + elif dep_libs_entry.endswith(".la"): + #Two cases: + #1) /usr/lib64/libfoo.la, turn it into -lfoo and append -L/usr/lib64 to libladir + #2) libfoo.la, keep it + dir, file = os.path.split(dep_libs_entry) + + if not dir or not file.startswith("lib"): + if dep_libs_entry not in new_dep_libs: + new_dep_libs.append(dep_libs_entry) + else: + #/usr/lib64/libfoo.la -> -lfoo + lib = "-l" + file[3:-3] + if lib not in new_dep_libs: + new_dep_libs.append(lib) + #/usr/lib64/libfoo.la -> -L/usr/lib64 + ladir = "-L" + dir + if ladir not in libladir: + libladir.append(ladir) + + elif dep_libs_entry.startswith("-L"): + #Do some replacement magic and store them in 'libladir'. + #This allows us to place all -L entries at the beginning + #of 'dependency_libs'. + ladir = dep_libs_entry + + ladir = X11_local_sub.sub("lib", ladir) + ladir = pkgconfig_sub1.sub("usr", ladir) + ladir = pkgconfig_sub2.sub("\g<usrlib>", ladir) + + if ladir not in libladir: + libladir.append(ladir) + + elif dep_libs_entry.startswith("-R"): + if dep_libs_entry not in librpath: + librpath.append(dep_libs_entry) + + elif flag_re.match(dep_libs_entry): + #All this stuff goes into inh_link_flags, if the la file has such an entry. + #If it doesn't, they stay in 'dependency_libs'. + if inh_link_flags is not None: + if dep_libs_entry not in new_inh_link_flags: + new_inh_link_flags.append(dep_libs_entry) + else: + if dep_libs_entry not in new_dep_libs: + new_dep_libs.append(dep_libs_entry) + + else: + raise InvalidData("Error: Unexpected entry '%s' in 'dependency_libs'" \ + % dep_libs_entry) + + #What should 'dependency_libs' and 'inherited_linker_flags' look like? + expected_dep_libs = "" + for x in (librpath, libladir, new_dep_libs): + if x: + expected_dep_libs += " " + " ".join(x) + + expected_inh_link_flags = "" + if new_inh_link_flags: + expected_inh_link_flags += " " + " ".join(new_inh_link_flags) + + #Don't touch the file if we don't need to, otherwise put the expected values into + #'contents' and write it into the la file. + if dep_libs == expected_dep_libs and \ + (inh_link_flags is None or expected_inh_link_flags == inh_link_flags): + return False, None + + contents = re.sub("dependency_libs='" + dep_libs + "'", \ + "dependency_libs='" + expected_dep_libs + "'" , contents) + + if inh_link_flags is not None: + contents = re.sub("inherited_linker_flags='" + inh_link_flags + "'", \ + "inherited_linker_flags='" + expected_inh_link_flags + "'" , contents) + + return True, contents |