mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
149 lines
5.8 KiB
Python
149 lines
5.8 KiB
Python
# ***** BEGIN LICENSE BLOCK *****
|
|
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
#
|
|
# The contents of this file are subject to the Mozilla Public License Version
|
|
# 1.1 (the "License"); you may not use this file except in compliance with
|
|
# the License. You may obtain a copy of the License at
|
|
# http://www.mozilla.org/MPL/
|
|
#
|
|
# Software distributed under the License is distributed on an "AS IS" basis,
|
|
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
# for the specific language governing rights and limitations under the
|
|
# License.
|
|
#
|
|
# The Original Code is a build helper for libraries
|
|
#
|
|
# The Initial Developer of the Original Code is
|
|
# the Mozilla Foundation
|
|
# Portions created by the Initial Developer are Copyright (C) 2011
|
|
# the Initial Developer. All Rights Reserved.
|
|
#
|
|
# Contributor(s):
|
|
# Mike Hommey <mh@glandium.org>
|
|
#
|
|
# Alternatively, the contents of this file may be used under the terms of
|
|
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
# in which case the provisions of the GPL or the LGPL are applicable instead
|
|
# of those above. If you wish to allow use of your version of this file only
|
|
# under the terms of either the GPL or the LGPL, and not to allow others to
|
|
# use your version of this file under the terms of the MPL, indicate your
|
|
# decision by deleting the provisions above and replace them with the notice
|
|
# and other provisions required by the GPL or the LGPL. If you do not delete
|
|
# the provisions above, a recipient may use your version of this file under
|
|
# the terms of any one of the MPL, the GPL or the LGPL.
|
|
#
|
|
# ***** END LICENSE BLOCK *****
|
|
|
|
'''Expandlibs is a system that allows to replace some libraries with a
|
|
descriptor file containing some linking information about them.
|
|
|
|
The descriptor file format is as follows:
|
|
---8<-----
|
|
OBJS = a.o b.o ...
|
|
LIBS = libfoo.a libbar.a ...
|
|
--->8-----
|
|
|
|
(In the example above, OBJ_SUFFIX is o and LIB_SUFFIX is a).
|
|
|
|
Expandlibs also canonicalizes how to pass libraries to the linker, such
|
|
that only the ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} form needs to be used:
|
|
given a list of files, expandlibs will replace items with the form
|
|
${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} following these rules:
|
|
|
|
- If a ${DLL_PREFIX}${ROOT}.${DLL_SUFFIX} or
|
|
${DLL_PREFIX}${ROOT}.${IMPORT_LIB_SUFFIX} file exists, use that instead
|
|
- If the ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} file exists, use it
|
|
- If a ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX}.${LIB_DESC_SUFFIX} file exists,
|
|
replace ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} with the OBJS and LIBS the
|
|
descriptor contains. And for each of these LIBS, also apply the same
|
|
rules.
|
|
'''
|
|
from __future__ import with_statement
|
|
import sys, os
|
|
import expandlibs_config as conf
|
|
|
|
def relativize(path):
|
|
'''Returns a path relative to the current working directory, if it is
|
|
shorter than the given path'''
|
|
def splitpath(path):
|
|
dir, file = os.path.split(path)
|
|
if os.path.splitdrive(dir)[1] == os.sep:
|
|
return [file]
|
|
return splitpath(dir) + [file]
|
|
|
|
if not os.path.exists(path):
|
|
return path
|
|
curdir = splitpath(os.path.abspath(os.curdir))
|
|
abspath = splitpath(os.path.abspath(path))
|
|
while curdir and abspath and curdir[0] == abspath[0]:
|
|
del curdir[0]
|
|
del abspath[0]
|
|
if not curdir and not abspath:
|
|
return '.'
|
|
relpath = os.path.join(*[os.pardir for i in curdir] + abspath)
|
|
if len(path) > len(relpath):
|
|
return relpath
|
|
return path
|
|
|
|
class LibDescriptor(dict):
|
|
KEYS = ['OBJS', 'LIBS']
|
|
|
|
def __init__(self, content=None):
|
|
'''Creates an instance of a lib descriptor, initialized with contents
|
|
from a list of strings when given. This is intended for use with
|
|
file.readlines()'''
|
|
if isinstance(content, list) and all([isinstance(item, str) for item in content]):
|
|
pass
|
|
elif content is not None:
|
|
raise TypeError("LibDescriptor() arg 1 must be None or a list of strings")
|
|
super(LibDescriptor, self).__init__()
|
|
for key in self.KEYS:
|
|
self[key] = []
|
|
if not content:
|
|
return
|
|
for key, value in [(s.strip() for s in item.split('=', 2)) for item in content if item.find('=') >= 0]:
|
|
if key in self.KEYS:
|
|
self[key] = value.split()
|
|
|
|
def __str__(self):
|
|
'''Serializes the lib descriptor'''
|
|
return '\n'.join('%s = %s' % (k, ' '.join(self[k])) for k in self.KEYS if len(self[k]))
|
|
|
|
class ExpandArgs(list):
|
|
def __init__(self, args):
|
|
'''Creates a clone of the |args| list and performs file expansion on
|
|
each item it contains'''
|
|
super(ExpandArgs, self).__init__()
|
|
for arg in args:
|
|
self += self._expand(arg)
|
|
|
|
def _expand(self, arg):
|
|
'''Internal function doing the actual work'''
|
|
(root, ext) = os.path.splitext(arg)
|
|
if ext != conf.LIB_SUFFIX or not os.path.basename(root).startswith(conf.LIB_PREFIX):
|
|
return [relativize(arg)]
|
|
if len(conf.IMPORT_LIB_SUFFIX):
|
|
dll = root + conf.IMPORT_LIB_SUFFIX
|
|
else:
|
|
dll = root.replace(conf.LIB_PREFIX, conf.DLL_PREFIX, 1) + conf.DLL_SUFFIX
|
|
if os.path.exists(dll):
|
|
return [relativize(dll)]
|
|
if os.path.exists(arg):
|
|
return [relativize(arg)]
|
|
return self._expand_desc(arg)
|
|
|
|
def _expand_desc(self, arg):
|
|
'''Internal function taking care of lib descriptor expansion only'''
|
|
if os.path.exists(arg + conf.LIBS_DESC_SUFFIX):
|
|
with open(arg + conf.LIBS_DESC_SUFFIX, 'r') as f:
|
|
desc = LibDescriptor(f.readlines())
|
|
objs = [relativize(o) for o in desc['OBJS']]
|
|
for lib in desc['LIBS']:
|
|
objs += self._expand(lib)
|
|
return objs
|
|
return [arg]
|
|
|
|
if __name__ == '__main__':
|
|
print " ".join(ExpandArgs(sys.argv[1:]))
|