1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/config/expandlibs.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,145 @@ 1.4 +# This Source Code Form is subject to the terms of the Mozilla Public 1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + 1.8 +'''Expandlibs is a system that allows to replace some libraries with a 1.9 +descriptor file containing some linking information about them. 1.10 + 1.11 +The descriptor file format is as follows: 1.12 +---8<----- 1.13 +OBJS = a.o b.o ... 1.14 +LIBS = libfoo.a libbar.a ... 1.15 +--->8----- 1.16 + 1.17 +(In the example above, OBJ_SUFFIX is o and LIB_SUFFIX is a). 1.18 + 1.19 +Expandlibs also canonicalizes how to pass libraries to the linker, such 1.20 +that only the ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} form needs to be used: 1.21 +given a list of files, expandlibs will replace items with the form 1.22 +${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} following these rules: 1.23 + 1.24 +- If a ${DLL_PREFIX}${ROOT}.${DLL_SUFFIX} or 1.25 + ${DLL_PREFIX}${ROOT}.${IMPORT_LIB_SUFFIX} file exists, use that instead 1.26 +- If the ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} file exists, use it 1.27 +- If a ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX}.${LIB_DESC_SUFFIX} file exists, 1.28 + replace ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} with the OBJS and LIBS the 1.29 + descriptor contains. And for each of these LIBS, also apply the same 1.30 + rules. 1.31 +''' 1.32 +from __future__ import with_statement 1.33 +import sys, os, errno 1.34 +import expandlibs_config as conf 1.35 + 1.36 +def ensureParentDir(file): 1.37 + '''Ensures the directory parent to the given file exists''' 1.38 + dir = os.path.dirname(file) 1.39 + if dir and not os.path.exists(dir): 1.40 + try: 1.41 + os.makedirs(dir) 1.42 + except OSError, error: 1.43 + if error.errno != errno.EEXIST: 1.44 + raise 1.45 + 1.46 +def relativize(path): 1.47 + '''Returns a path relative to the current working directory, if it is 1.48 + shorter than the given path''' 1.49 + def splitpath(path): 1.50 + dir, file = os.path.split(path) 1.51 + if os.path.splitdrive(dir)[1] == os.sep: 1.52 + return [file] 1.53 + return splitpath(dir) + [file] 1.54 + 1.55 + if not os.path.exists(path): 1.56 + return path 1.57 + curdir = splitpath(os.path.abspath(os.curdir)) 1.58 + abspath = splitpath(os.path.abspath(path)) 1.59 + while curdir and abspath and curdir[0] == abspath[0]: 1.60 + del curdir[0] 1.61 + del abspath[0] 1.62 + if not curdir and not abspath: 1.63 + return '.' 1.64 + relpath = os.path.join(*[os.pardir for i in curdir] + abspath) 1.65 + if len(path) > len(relpath): 1.66 + return relpath 1.67 + return path 1.68 + 1.69 +def isObject(path): 1.70 + '''Returns whether the given path points to an object file, that is, 1.71 + ends with OBJ_SUFFIX or .i_o''' 1.72 + return os.path.splitext(path)[1] in [conf.OBJ_SUFFIX, '.i_o'] 1.73 + 1.74 +def isDynamicLib(path): 1.75 + '''Returns whether the given path points to a dynamic library, that is, 1.76 + ends with DLL_SUFFIX.''' 1.77 + # On mac, the xul library is named XUL, instead of libxul.dylib. Assume any 1.78 + # file by that name is a dynamic library. 1.79 + return os.path.splitext(path)[1] == conf.DLL_SUFFIX or os.path.basename(path) == 'XUL' 1.80 + 1.81 +class LibDescriptor(dict): 1.82 + KEYS = ['OBJS', 'LIBS'] 1.83 + 1.84 + def __init__(self, content=None): 1.85 + '''Creates an instance of a lib descriptor, initialized with contents 1.86 + from a list of strings when given. This is intended for use with 1.87 + file.readlines()''' 1.88 + if isinstance(content, list) and all([isinstance(item, str) for item in content]): 1.89 + pass 1.90 + elif content is not None: 1.91 + raise TypeError("LibDescriptor() arg 1 must be None or a list of strings") 1.92 + super(LibDescriptor, self).__init__() 1.93 + for key in self.KEYS: 1.94 + self[key] = [] 1.95 + if not content: 1.96 + return 1.97 + for key, value in [(s.strip() for s in item.split('=', 2)) for item in content if item.find('=') >= 0]: 1.98 + if key in self.KEYS: 1.99 + self[key] = value.split() 1.100 + 1.101 + def __str__(self): 1.102 + '''Serializes the lib descriptor''' 1.103 + return '\n'.join('%s = %s' % (k, ' '.join(self[k])) for k in self.KEYS if len(self[k])) 1.104 + 1.105 +class ExpandArgs(list): 1.106 + def __init__(self, args): 1.107 + '''Creates a clone of the |args| list and performs file expansion on 1.108 + each item it contains''' 1.109 + super(ExpandArgs, self).__init__() 1.110 + for arg in args: 1.111 + self += self._expand(arg) 1.112 + 1.113 + def _expand(self, arg): 1.114 + '''Internal function doing the actual work''' 1.115 + (root, ext) = os.path.splitext(arg) 1.116 + if ext != conf.LIB_SUFFIX or not os.path.basename(root).startswith(conf.LIB_PREFIX): 1.117 + return [relativize(arg)] 1.118 + if len(conf.IMPORT_LIB_SUFFIX): 1.119 + dll = root + conf.IMPORT_LIB_SUFFIX 1.120 + else: 1.121 + dll = root.replace(conf.LIB_PREFIX, conf.DLL_PREFIX, 1) + conf.DLL_SUFFIX 1.122 + if os.path.exists(dll): 1.123 + return [relativize(dll)] 1.124 + if os.path.exists(arg): 1.125 + return [relativize(arg)] 1.126 + return self._expand_desc(arg) 1.127 + 1.128 + def _expand_desc(self, arg): 1.129 + '''Internal function taking care of lib descriptor expansion only''' 1.130 + if os.path.exists(arg + conf.LIBS_DESC_SUFFIX): 1.131 + with open(arg + conf.LIBS_DESC_SUFFIX, 'r') as f: 1.132 + desc = LibDescriptor(f.readlines()) 1.133 + objs = [relativize(o) for o in desc['OBJS']] 1.134 + for lib in desc['LIBS']: 1.135 + objs += self._expand(lib) 1.136 + return objs 1.137 + return [arg] 1.138 + 1.139 +class ExpandLibsDeps(ExpandArgs): 1.140 + '''Same as ExpandArgs, but also adds the library descriptor to the list''' 1.141 + def _expand_desc(self, arg): 1.142 + objs = super(ExpandLibsDeps, self)._expand_desc(arg) 1.143 + if os.path.exists(arg + conf.LIBS_DESC_SUFFIX): 1.144 + objs += [relativize(arg + conf.LIBS_DESC_SUFFIX)] 1.145 + return objs 1.146 + 1.147 +if __name__ == '__main__': 1.148 + print " ".join(ExpandArgs(sys.argv[1:]))