1
# This Source Code Form is subject to the terms of the Mozilla Public
2
# License, v. 2.0. If a copy of the MPL was not distributed with this
3
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
'''Expandlibs is a system that allows to replace some libraries with a
6
descriptor file containing some linking information about them.
8
The descriptor file format is as follows:
11
LIBS = libfoo.a libbar.a ...
14
(In the example above, OBJ_SUFFIX is o and LIB_SUFFIX is a).
16
Expandlibs also canonicalizes how to pass libraries to the linker, such
17
that only the ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} form needs to be used:
18
given a list of files, expandlibs will replace items with the form
19
${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} following these rules:
21
- If a ${DLL_PREFIX}${ROOT}.${DLL_SUFFIX} or
22
${DLL_PREFIX}${ROOT}.${IMPORT_LIB_SUFFIX} file exists, use that instead
23
- If the ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} file exists, use it
24
- If a ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX}.${LIB_DESC_SUFFIX} file exists,
25
replace ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} with the OBJS and LIBS the
26
descriptor contains. And for each of these LIBS, also apply the same
29
from __future__ import with_statement
31
import expandlibs_config as conf
33
def ensureParentDir(file):
34
'''Ensures the directory parent to the given file exists'''
35
dir = os.path.dirname(file)
36
if dir and not os.path.exists(dir):
39
except OSError, error:
40
if error.errno != errno.EEXIST:
44
'''Returns a path relative to the current working directory, if it is
45
shorter than the given path'''
47
dir, file = os.path.split(path)
48
if os.path.splitdrive(dir)[1] == os.sep:
50
return splitpath(dir) + [file]
52
if not os.path.exists(path):
54
curdir = splitpath(os.path.abspath(os.curdir))
55
abspath = splitpath(os.path.abspath(path))
56
while curdir and abspath and curdir[0] == abspath[0]:
59
if not curdir and not abspath:
61
relpath = os.path.join(*[os.pardir for i in curdir] + abspath)
62
if len(path) > len(relpath):
67
'''Returns whether the given path points to an object file, that is,
68
ends with OBJ_SUFFIX or .i_o'''
69
return os.path.splitext(path)[1] in [conf.OBJ_SUFFIX, '.i_o']
71
class LibDescriptor(dict):
72
KEYS = ['OBJS', 'LIBS']
74
def __init__(self, content=None):
75
'''Creates an instance of a lib descriptor, initialized with contents
76
from a list of strings when given. This is intended for use with
78
if isinstance(content, list) and all([isinstance(item, str) for item in content]):
80
elif content is not None:
81
raise TypeError("LibDescriptor() arg 1 must be None or a list of strings")
82
super(LibDescriptor, self).__init__()
87
for key, value in [(s.strip() for s in item.split('=', 2)) for item in content if item.find('=') >= 0]:
89
self[key] = value.split()
92
'''Serializes the lib descriptor'''
93
return '\n'.join('%s = %s' % (k, ' '.join(self[k])) for k in self.KEYS if len(self[k]))
95
class ExpandArgs(list):
96
def __init__(self, args):
97
'''Creates a clone of the |args| list and performs file expansion on
98
each item it contains'''
99
super(ExpandArgs, self).__init__()
101
self += self._expand(arg)
103
def _expand(self, arg):
104
'''Internal function doing the actual work'''
105
(root, ext) = os.path.splitext(arg)
106
if ext != conf.LIB_SUFFIX or not os.path.basename(root).startswith(conf.LIB_PREFIX):
107
return [relativize(arg)]
108
if len(conf.IMPORT_LIB_SUFFIX):
109
dll = root + conf.IMPORT_LIB_SUFFIX
111
dll = root.replace(conf.LIB_PREFIX, conf.DLL_PREFIX, 1) + conf.DLL_SUFFIX
112
if os.path.exists(dll):
113
return [relativize(dll)]
114
if os.path.exists(arg):
115
return [relativize(arg)]
116
return self._expand_desc(arg)
118
def _expand_desc(self, arg):
119
'''Internal function taking care of lib descriptor expansion only'''
120
if os.path.exists(arg + conf.LIBS_DESC_SUFFIX):
121
with open(arg + conf.LIBS_DESC_SUFFIX, 'r') as f:
122
desc = LibDescriptor(f.readlines())
123
objs = [relativize(o) for o in desc['OBJS']]
124
for lib in desc['LIBS']:
125
objs += self._expand(lib)
129
class ExpandLibsDeps(ExpandArgs):
130
'''Same as ExpandArgs, but also adds the library descriptor to the list'''
131
def _expand_desc(self, arg):
132
objs = super(ExpandLibsDeps, self)._expand_desc(arg)
133
if os.path.exists(arg + conf.LIBS_DESC_SUFFIX):
134
objs += [relativize(arg + conf.LIBS_DESC_SUFFIX)]
137
if __name__ == '__main__':
138
print " ".join(ExpandArgs(sys.argv[1:]))