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 def isDynamicLib(path
):
72 '''Returns whether the given path points to a dynamic library, that is,
73 ends with DLL_SUFFIX.'''
74 # On mac, the xul library is named XUL, instead of libxul.dylib. Assume any
75 # file by that name is a dynamic library.
76 return os
.path
.splitext(path
)[1] == conf
.DLL_SUFFIX
or os
.path
.basename(path
) == 'XUL'
78 class LibDescriptor(dict):
79 KEYS
= ['OBJS', 'LIBS']
81 def __init__(self
, content
=None):
82 '''Creates an instance of a lib descriptor, initialized with contents
83 from a list of strings when given. This is intended for use with
85 if isinstance(content
, list) and all([isinstance(item
, str) for item
in content
]):
87 elif content
is not None:
88 raise TypeError("LibDescriptor() arg 1 must be None or a list of strings")
89 super(LibDescriptor
, self
).__init
__()
94 for key
, value
in [(s
.strip() for s
in item
.split('=', 2)) for item
in content
if item
.find('=') >= 0]:
96 self
[key
] = value
.split()
99 '''Serializes the lib descriptor'''
100 return '\n'.join('%s = %s' % (k
, ' '.join(self
[k
])) for k
in self
.KEYS
if len(self
[k
]))
102 class ExpandArgs(list):
103 def __init__(self
, args
):
104 '''Creates a clone of the |args| list and performs file expansion on
105 each item it contains'''
106 super(ExpandArgs
, self
).__init
__()
109 self
+= self
._expand
(arg
)
111 def _expand(self
, arg
):
112 '''Internal function doing the actual work'''
113 (root
, ext
) = os
.path
.splitext(arg
)
114 if ext
!= conf
.LIB_SUFFIX
or not os
.path
.basename(root
).startswith(conf
.LIB_PREFIX
):
115 return [relativize(arg
)]
116 if len(conf
.IMPORT_LIB_SUFFIX
):
117 dll
= root
+ conf
.IMPORT_LIB_SUFFIX
119 dll
= root
.replace(conf
.LIB_PREFIX
, conf
.DLL_PREFIX
, 1) + conf
.DLL_SUFFIX
120 if os
.path
.exists(dll
):
121 return [relativize(dll
)]
122 if os
.path
.exists(arg
):
123 return [relativize(arg
)]
124 return self
._expand
_desc
(arg
)
126 def _expand_desc(self
, arg
):
127 '''Internal function taking care of lib descriptor expansion only'''
128 desc
= os
.path
.abspath(arg
+ conf
.LIBS_DESC_SUFFIX
)
129 if os
.path
.exists(desc
):
130 if desc
in self
._descs
:
132 self
._descs
.add(desc
)
133 with
open(desc
, 'r') as f
:
134 desc
= LibDescriptor(f
.readlines())
135 objs
= [relativize(o
) for o
in desc
['OBJS']]
136 for lib
in desc
['LIBS']:
137 objs
+= self
._expand
(lib
)
141 if __name__
== '__main__':
142 print " ".join(ExpandArgs(sys
.argv
[1:]))