#!/usr/bin/env python # encoding: utf-8 # Matthias Jahn, 2008, jahn matthias ath freenet punto de # Thomas Nagy, 2008 (ita) import sys, re, os, optparse import TaskGen, Task, Utils, preproc from Logs import error, debug, warn from TaskGen import taskgen, after, before, feature REVISION="0.1.3" """ if you want to use the code here, you must use something like this: obj = obj.create(...) obj.features.append("libtool") obj.vnum = "1.2.3" # optional, but versioned libraries are common """ # fake libtool files fakelibtool_vardeps = ['CXX', 'PREFIX'] def fakelibtool_build(task): # Writes a .la file, used by libtool env = task.env dest = open(task.outputs[0].abspath(env), 'w') sname = task.inputs[0].name fu = dest.write fu("# Generated by ltmain.sh - GNU libtool 1.5.18 - (pwn3d by BKsys II code name WAF)\n") if env['vnum']: nums = env['vnum'].split('.') libname = task.inputs[0].name name3 = libname+'.'+env['vnum'] name2 = libname+'.'+nums[0] name1 = libname fu("dlname='%s'\n" % name2) strn = " ".join([name3, name2, name1]) fu("library_names='%s'\n" % (strn) ) else: fu("dlname='%s'\n" % sname) fu("library_names='%s %s %s'\n" % (sname, sname, sname) ) fu("old_library=''\n") vars = ' '.join(env['libtoolvars']+env['LINKFLAGS']) fu("dependency_libs='%s'\n" % vars) fu("current=0\n") fu("age=0\nrevision=0\ninstalled=yes\nshouldnotlink=no\n") fu("dlopen=''\ndlpreopen=''\n") fu("libdir='%s/lib'\n" % env['PREFIX']) dest.close() return 0 def read_la_file(path): sp = re.compile(r'^([^=]+)=\'(.*)\'$') dc={} file = open(path, "r") for line in file.readlines(): try: #print sp.split(line.strip()) _, left, right, _ = sp.split(line.strip()) dc[left]=right except ValueError: pass file.close() return dc @feature("libtool") @after('apply_link') def apply_link_libtool(self): if self.type != 'program': linktask = self.link_task latask = self.create_task('fakelibtool') latask.set_inputs(linktask.outputs) latask.set_outputs(linktask.outputs[0].change_ext('.la')) self.latask = latask if self.bld.is_install: self.bld.install_files('${PREFIX}/lib', linktask.outputs[0], self.env) @feature("libtool") @before('apply_core') def apply_libtool(self): self.env['vnum']=self.vnum paths=[] libs=[] libtool_files=[] libtool_vars=[] for l in self.env['LINKFLAGS']: if l[:2]=='-L': paths.append(l[2:]) elif l[:2]=='-l': libs.append(l[2:]) for l in libs: for p in paths: dict = read_la_file(p+'/lib'+l+'.la') linkflags2 = dict.get('dependency_libs', '') for v in linkflags2.split(): if v.endswith('.la'): libtool_files.append(v) libtool_vars.append(v) continue self.env.append_unique('LINKFLAGS', v) break self.env['libtoolvars']=libtool_vars while libtool_files: file = libtool_files.pop() dict = read_la_file(file) for v in dict['dependency_libs'].split(): if v[-3:] == '.la': libtool_files.append(v) continue self.env.append_unique('LINKFLAGS', v) Task.task_type_from_func('fakelibtool', vars=fakelibtool_vardeps, func=fakelibtool_build, color='BLUE', after="cc_link cxx_link static_link") class libtool_la_file: def __init__ (self, la_filename): self.__la_filename = la_filename #remove path and .la suffix self.linkname = str(os.path.split(la_filename)[-1])[:-3] if self.linkname.startswith("lib"): self.linkname = self.linkname[3:] # The name that we can dlopen(3). self.dlname = None # Names of this library self.library_names = None # The name of the static archive. self.old_library = None # Libraries that this one depends upon. self.dependency_libs = None # Version information for libIlmImf. self.current = None self.age = None self.revision = None # Is this an already installed library? self.installed = None # Should we warn about portability when linking against -modules? self.shouldnotlink = None # Files to dlopen/dlpreopen self.dlopen = None self.dlpreopen = None # Directory that this library needs to be installed in: self.libdir = '/usr/lib' if not self.__parse(): raise "file %s not found!!" %(la_filename) def __parse(self): "Retrieve the variables from a file" if not os.path.isfile(self.__la_filename): return 0 la_file=open(self.__la_filename, 'r') for line in la_file: ln = line.strip() if not ln: continue if ln[0]=='#': continue (key, value) = str(ln).split('=', 1) key = key.strip() value = value.strip() if value == "no": value = False elif value == "yes": value = True else: try: value = int(value) except ValueError: value = value.strip("'") setattr(self, key, value) la_file.close() return 1 def get_libs(self): """return linkflags for this lib""" libs = [] if self.dependency_libs: libs = str(self.dependency_libs).strip().split() if libs == None: libs = [] # add la lib and libdir libs.insert(0, "-l%s" % self.linkname.strip()) libs.insert(0, "-L%s" % self.libdir.strip()) return libs def __str__(self): return '''\ dlname = "%(dlname)s" library_names = "%(library_names)s" old_library = "%(old_library)s" dependency_libs = "%(dependency_libs)s" version = %(current)s.%(age)s.%(revision)s installed = "%(installed)s" shouldnotlink = "%(shouldnotlink)s" dlopen = "%(dlopen)s" dlpreopen = "%(dlpreopen)s" libdir = "%(libdir)s"''' % self.__dict__ class libtool_config: def __init__ (self, la_filename): self.__libtool_la_file = libtool_la_file(la_filename) tmp = self.__libtool_la_file self.__version = [int(tmp.current), int(tmp.age), int(tmp.revision)] self.__sub_la_files = [] self.__sub_la_files.append(la_filename) self.__libs = None def __cmp__(self, other): """make it compareable with X.Y.Z versions (Y and Z are optional)""" if not other: return 1 othervers = [int(s) for s in str(other).split(".")] selfvers = self.__version return cmp(selfvers, othervers) def __str__(self): return "\n".join([ str(self.__libtool_la_file), ' '.join(self.__libtool_la_file.get_libs()), '* New getlibs:', ' '.join(self.get_libs()) ]) def __get_la_libs(self, la_filename): return libtool_la_file(la_filename).get_libs() def get_libs(self): """return the complete uniqe linkflags that do not contain .la files anymore""" libs_list = list(self.__libtool_la_file.get_libs()) libs_map = {} while len(libs_list) > 0: entry = libs_list.pop(0) if entry: if str(entry).endswith(".la"): ## prevents duplicate .la checks if entry not in self.__sub_la_files: self.__sub_la_files.append(entry) libs_list.extend(self.__get_la_libs(entry)) else: libs_map[entry]=1 self.__libs = libs_map.keys() return self.__libs def get_libs_only_L(self): if not self.__libs: self.get_libs() libs = self.__libs libs = [s for s in libs if str(s).startswith('-L')] return libs def get_libs_only_l(self): if not self.__libs: self.get_libs() libs = self.__libs libs = [s for s in libs if str(s).startswith('-l')] return libs def get_libs_only_other(self): if not self.__libs: self.get_libs() libs = self.__libs libs = [s for s in libs if not(str(s).startswith('-L')or str(s).startswith('-l'))] return libs def useCmdLine(): """parse cmdline args and control build""" usage = '''Usage: %prog [options] PathToFile.la example: %prog --atleast-version=2.0.0 /usr/lib/libIlmImf.la nor: %prog --libs /usr/lib/libamarok.la''' parser = optparse.OptionParser(usage) a = parser.add_option a("--version", dest = "versionNumber", action = "store_true", default = False, help = "output version of libtool-config" ) a("--debug", dest = "debug", action = "store_true", default = False, help = "enable debug" ) a("--libs", dest = "libs", action = "store_true", default = False, help = "output all linker flags" ) a("--libs-only-l", dest = "libs_only_l", action = "store_true", default = False, help = "output -l flags" ) a("--libs-only-L", dest = "libs_only_L", action = "store_true", default = False, help = "output -L flags" ) a("--libs-only-other", dest = "libs_only_other", action = "store_true", default = False, help = "output other libs (e.g. -pthread)" ) a("--atleast-version", dest = "atleast_version", default=None, help = "return 0 if the module is at least version ATLEAST_VERSION" ) a("--exact-version", dest = "exact_version", default=None, help = "return 0 if the module is exactly version EXACT_VERSION" ) a("--max-version", dest = "max_version", default=None, help = "return 0 if the module is at no newer than version MAX_VERSION" ) (options, args) = parser.parse_args() if len(args) != 1 and not options.versionNumber: parser.error("incorrect number of arguments") if options.versionNumber: print("libtool-config version %s" % REVISION) return 0 ltf = libtool_config(args[0]) if options.debug: print(ltf) if options.atleast_version: if ltf >= options.atleast_version: return 0 sys.exit(1) if options.exact_version: if ltf == options.exact_version: return 0 sys.exit(1) if options.max_version: if ltf <= options.max_version: return 0 sys.exit(1) def p(x): print(" ".join(x)) if options.libs: p(ltf.get_libs()) elif options.libs_only_l: p(ltf.get_libs_only_l()) elif options.libs_only_L: p(ltf.get_libs_only_L()) elif options.libs_only_other: p(ltf.get_libs_only_other()) return 0 if __name__ == '__main__': useCmdLine()