summaryrefslogtreecommitdiffstats
path: root/pym/portage/util/lafilefixer.py
diff options
context:
space:
mode:
authorSebastian Luther <SebastianLuther@gmx.de>2010-07-12 10:41:32 +0200
committerZac Medico <zmedico@gentoo.org>2010-07-12 02:34:06 -0700
commit76118ef9b746ca3ba644504b6ddb13906bc2e2f0 (patch)
tree4f1000c2d2570f12dc86684671c13093f14433ce /pym/portage/util/lafilefixer.py
parent32264c30d8fc23f08f30f1488a1fa68d1f2cfc34 (diff)
downloadportage-76118ef9b746ca3ba644504b6ddb13906bc2e2f0.tar.gz
portage-76118ef9b746ca3ba644504b6ddb13906bc2e2f0.tar.bz2
portage-76118ef9b746ca3ba644504b6ddb13906bc2e2f0.zip
Let emerge fix .la files
Triggered by FEATURES="lafilefixing" (enabled by default) Includes a QA warning for invalid .la files.
Diffstat (limited to 'pym/portage/util/lafilefixer.py')
-rw-r--r--pym/portage/util/lafilefixer.py176
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