config/expandlibs.py

changeset 0
6474c204b198
     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:]))

mercurial