s3: Fix idmap_hash
[Samba/gebeck_regimport.git] / buildtools / wafadmin / Tools / libtool.py
blob47fa906fcccb2ca2d0decc72a80cebd77681e883
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Matthias Jahn, 2008, jahn matthias ath freenet punto de
4 # Thomas Nagy, 2008 (ita)
6 import sys, re, os, optparse
8 import TaskGen, Task, Utils, preproc
9 from Logs import error, debug, warn
10 from TaskGen import taskgen, after, before, feature
12 REVISION="0.1.3"
14 """
15 if you want to use the code here, you must use something like this:
16 obj = obj.create(...)
17 obj.features.append("libtool")
18 obj.vnum = "1.2.3" # optional, but versioned libraries are common
19 """
21 # fake libtool files
22 fakelibtool_vardeps = ['CXX', 'PREFIX']
23 def fakelibtool_build(task):
24 # Writes a .la file, used by libtool
25 env = task.env
26 dest = open(task.outputs[0].abspath(env), 'w')
27 sname = task.inputs[0].name
28 fu = dest.write
29 fu("# Generated by ltmain.sh - GNU libtool 1.5.18 - (pwn3d by BKsys II code name WAF)\n")
30 if env['vnum']:
31 nums = env['vnum'].split('.')
32 libname = task.inputs[0].name
33 name3 = libname+'.'+env['vnum']
34 name2 = libname+'.'+nums[0]
35 name1 = libname
36 fu("dlname='%s'\n" % name2)
37 strn = " ".join([name3, name2, name1])
38 fu("library_names='%s'\n" % (strn) )
39 else:
40 fu("dlname='%s'\n" % sname)
41 fu("library_names='%s %s %s'\n" % (sname, sname, sname) )
42 fu("old_library=''\n")
43 vars = ' '.join(env['libtoolvars']+env['LINKFLAGS'])
44 fu("dependency_libs='%s'\n" % vars)
45 fu("current=0\n")
46 fu("age=0\nrevision=0\ninstalled=yes\nshouldnotlink=no\n")
47 fu("dlopen=''\ndlpreopen=''\n")
48 fu("libdir='%s/lib'\n" % env['PREFIX'])
49 dest.close()
50 return 0
52 def read_la_file(path):
53 sp = re.compile(r'^([^=]+)=\'(.*)\'$')
54 dc={}
55 file = open(path, "r")
56 for line in file.readlines():
57 try:
58 #print sp.split(line.strip())
59 _, left, right, _ = sp.split(line.strip())
60 dc[left]=right
61 except ValueError:
62 pass
63 file.close()
64 return dc
66 @feature("libtool")
67 @after('apply_link')
68 def apply_link_libtool(self):
69 if self.type != 'program':
70 linktask = self.link_task
71 self.latask = self.create_task('fakelibtool', linktask.outputs, linktask.outputs[0].change_ext('.la'))
73 if self.bld.is_install:
74 self.bld.install_files('${PREFIX}/lib', linktask.outputs[0], self.env)
76 @feature("libtool")
77 @before('apply_core')
78 def apply_libtool(self):
79 self.env['vnum']=self.vnum
81 paths=[]
82 libs=[]
83 libtool_files=[]
84 libtool_vars=[]
86 for l in self.env['LINKFLAGS']:
87 if l[:2]=='-L':
88 paths.append(l[2:])
89 elif l[:2]=='-l':
90 libs.append(l[2:])
92 for l in libs:
93 for p in paths:
94 dict = read_la_file(p+'/lib'+l+'.la')
95 linkflags2 = dict.get('dependency_libs', '')
96 for v in linkflags2.split():
97 if v.endswith('.la'):
98 libtool_files.append(v)
99 libtool_vars.append(v)
100 continue
101 self.env.append_unique('LINKFLAGS', v)
102 break
104 self.env['libtoolvars']=libtool_vars
106 while libtool_files:
107 file = libtool_files.pop()
108 dict = read_la_file(file)
109 for v in dict['dependency_libs'].split():
110 if v[-3:] == '.la':
111 libtool_files.append(v)
112 continue
113 self.env.append_unique('LINKFLAGS', v)
115 Task.task_type_from_func('fakelibtool', vars=fakelibtool_vardeps, func=fakelibtool_build, color='BLUE', after="cc_link cxx_link static_link")
117 class libtool_la_file:
118 def __init__ (self, la_filename):
119 self.__la_filename = la_filename
120 #remove path and .la suffix
121 self.linkname = str(os.path.split(la_filename)[-1])[:-3]
122 if self.linkname.startswith("lib"):
123 self.linkname = self.linkname[3:]
124 # The name that we can dlopen(3).
125 self.dlname = None
126 # Names of this library
127 self.library_names = None
128 # The name of the static archive.
129 self.old_library = None
130 # Libraries that this one depends upon.
131 self.dependency_libs = None
132 # Version information for libIlmImf.
133 self.current = None
134 self.age = None
135 self.revision = None
136 # Is this an already installed library?
137 self.installed = None
138 # Should we warn about portability when linking against -modules?
139 self.shouldnotlink = None
140 # Files to dlopen/dlpreopen
141 self.dlopen = None
142 self.dlpreopen = None
143 # Directory that this library needs to be installed in:
144 self.libdir = '/usr/lib'
145 if not self.__parse():
146 raise ValueError("file %s not found!!" %(la_filename))
148 def __parse(self):
149 "Retrieve the variables from a file"
150 if not os.path.isfile(self.__la_filename): return 0
151 la_file=open(self.__la_filename, 'r')
152 for line in la_file:
153 ln = line.strip()
154 if not ln: continue
155 if ln[0]=='#': continue
156 (key, value) = str(ln).split('=', 1)
157 key = key.strip()
158 value = value.strip()
159 if value == "no": value = False
160 elif value == "yes": value = True
161 else:
162 try: value = int(value)
163 except ValueError: value = value.strip("'")
164 setattr(self, key, value)
165 la_file.close()
166 return 1
168 def get_libs(self):
169 """return linkflags for this lib"""
170 libs = []
171 if self.dependency_libs:
172 libs = str(self.dependency_libs).strip().split()
173 if libs == None:
174 libs = []
175 # add la lib and libdir
176 libs.insert(0, "-l%s" % self.linkname.strip())
177 libs.insert(0, "-L%s" % self.libdir.strip())
178 return libs
180 def __str__(self):
181 return '''\
182 dlname = "%(dlname)s"
183 library_names = "%(library_names)s"
184 old_library = "%(old_library)s"
185 dependency_libs = "%(dependency_libs)s"
186 version = %(current)s.%(age)s.%(revision)s
187 installed = "%(installed)s"
188 shouldnotlink = "%(shouldnotlink)s"
189 dlopen = "%(dlopen)s"
190 dlpreopen = "%(dlpreopen)s"
191 libdir = "%(libdir)s"''' % self.__dict__
193 class libtool_config:
194 def __init__ (self, la_filename):
195 self.__libtool_la_file = libtool_la_file(la_filename)
196 tmp = self.__libtool_la_file
197 self.__version = [int(tmp.current), int(tmp.age), int(tmp.revision)]
198 self.__sub_la_files = []
199 self.__sub_la_files.append(la_filename)
200 self.__libs = None
202 def __cmp__(self, other):
203 """make it compareable with X.Y.Z versions (Y and Z are optional)"""
204 if not other:
205 return 1
206 othervers = [int(s) for s in str(other).split(".")]
207 selfvers = self.__version
208 return cmp(selfvers, othervers)
210 def __str__(self):
211 return "\n".join([
212 str(self.__libtool_la_file),
213 ' '.join(self.__libtool_la_file.get_libs()),
214 '* New getlibs:',
215 ' '.join(self.get_libs())
218 def __get_la_libs(self, la_filename):
219 return libtool_la_file(la_filename).get_libs()
221 def get_libs(self):
222 """return the complete uniqe linkflags that do not
223 contain .la files anymore"""
224 libs_list = list(self.__libtool_la_file.get_libs())
225 libs_map = {}
226 while len(libs_list) > 0:
227 entry = libs_list.pop(0)
228 if entry:
229 if str(entry).endswith(".la"):
230 ## prevents duplicate .la checks
231 if entry not in self.__sub_la_files:
232 self.__sub_la_files.append(entry)
233 libs_list.extend(self.__get_la_libs(entry))
234 else:
235 libs_map[entry]=1
236 self.__libs = libs_map.keys()
237 return self.__libs
239 def get_libs_only_L(self):
240 if not self.__libs: self.get_libs()
241 libs = self.__libs
242 libs = [s for s in libs if str(s).startswith('-L')]
243 return libs
245 def get_libs_only_l(self):
246 if not self.__libs: self.get_libs()
247 libs = self.__libs
248 libs = [s for s in libs if str(s).startswith('-l')]
249 return libs
251 def get_libs_only_other(self):
252 if not self.__libs: self.get_libs()
253 libs = self.__libs
254 libs = [s for s in libs if not(str(s).startswith('-L')or str(s).startswith('-l'))]
255 return libs
257 def useCmdLine():
258 """parse cmdline args and control build"""
259 usage = '''Usage: %prog [options] PathToFile.la
260 example: %prog --atleast-version=2.0.0 /usr/lib/libIlmImf.la
261 nor: %prog --libs /usr/lib/libamarok.la'''
262 parser = optparse.OptionParser(usage)
263 a = parser.add_option
264 a("--version", dest = "versionNumber",
265 action = "store_true", default = False,
266 help = "output version of libtool-config"
268 a("--debug", dest = "debug",
269 action = "store_true", default = False,
270 help = "enable debug"
272 a("--libs", dest = "libs",
273 action = "store_true", default = False,
274 help = "output all linker flags"
276 a("--libs-only-l", dest = "libs_only_l",
277 action = "store_true", default = False,
278 help = "output -l flags"
280 a("--libs-only-L", dest = "libs_only_L",
281 action = "store_true", default = False,
282 help = "output -L flags"
284 a("--libs-only-other", dest = "libs_only_other",
285 action = "store_true", default = False,
286 help = "output other libs (e.g. -pthread)"
288 a("--atleast-version", dest = "atleast_version",
289 default=None,
290 help = "return 0 if the module is at least version ATLEAST_VERSION"
292 a("--exact-version", dest = "exact_version",
293 default=None,
294 help = "return 0 if the module is exactly version EXACT_VERSION"
296 a("--max-version", dest = "max_version",
297 default=None,
298 help = "return 0 if the module is at no newer than version MAX_VERSION"
301 (options, args) = parser.parse_args()
302 if len(args) != 1 and not options.versionNumber:
303 parser.error("incorrect number of arguments")
304 if options.versionNumber:
305 print("libtool-config version %s" % REVISION)
306 return 0
307 ltf = libtool_config(args[0])
308 if options.debug:
309 print(ltf)
310 if options.atleast_version:
311 if ltf >= options.atleast_version: return 0
312 sys.exit(1)
313 if options.exact_version:
314 if ltf == options.exact_version: return 0
315 sys.exit(1)
316 if options.max_version:
317 if ltf <= options.max_version: return 0
318 sys.exit(1)
320 def p(x):
321 print(" ".join(x))
322 if options.libs: p(ltf.get_libs())
323 elif options.libs_only_l: p(ltf.get_libs_only_l())
324 elif options.libs_only_L: p(ltf.get_libs_only_L())
325 elif options.libs_only_other: p(ltf.get_libs_only_other())
326 return 0
328 if __name__ == '__main__':
329 useCmdLine()