1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/build/subconfigure.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,137 @@ 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 +# This script is used to capture the content of config.status-generated 1.9 +# files and subsequently restore their timestamp if they haven't changed. 1.10 + 1.11 +import os 1.12 +import re 1.13 +import subprocess 1.14 +import sys 1.15 +import pickle 1.16 + 1.17 +class File(object): 1.18 + def __init__(self, path): 1.19 + self._path = path 1.20 + self._content = open(path, 'rb').read() 1.21 + stat = os.stat(path) 1.22 + self._times = (stat.st_atime, stat.st_mtime) 1.23 + 1.24 + @property 1.25 + def path(self): 1.26 + return self._path 1.27 + 1.28 + @property 1.29 + def mtime(self): 1.30 + return self._times[1] 1.31 + 1.32 + def update_time(self): 1.33 + '''If the file hasn't changed since the instance was created, 1.34 + restore its old modification time.''' 1.35 + if not os.path.exists(self._path): 1.36 + return 1.37 + if open(self._path, 'rb').read() == self._content: 1.38 + os.utime(self._path, self._times) 1.39 + 1.40 + 1.41 +# As defined in the various sub-configures in the tree 1.42 +PRECIOUS_VARS = set([ 1.43 + 'build_alias', 1.44 + 'host_alias', 1.45 + 'target_alias', 1.46 + 'CC', 1.47 + 'CFLAGS', 1.48 + 'LDFLAGS', 1.49 + 'LIBS', 1.50 + 'CPPFLAGS', 1.51 + 'CPP', 1.52 + 'CCC', 1.53 + 'CXXFLAGS', 1.54 + 'CXX', 1.55 + 'CCASFLAGS', 1.56 + 'CCAS', 1.57 +]) 1.58 + 1.59 + 1.60 +# Autoconf, in some of the sub-configures used in the tree, likes to error 1.61 +# out when "precious" variables change in value. The solution it gives to 1.62 +# straighten things is to either run make distclean or remove config.cache. 1.63 +# There's no reason not to do the latter automatically instead of failing, 1.64 +# doing the cleanup (which, on buildbots means a full clobber), and 1.65 +# restarting from scratch. 1.66 +def maybe_clear_cache(): 1.67 + comment = re.compile(r'^\s+#') 1.68 + cache = {} 1.69 + with open('config.cache') as f: 1.70 + for line in f.readlines(): 1.71 + if not comment.match(line) and '=' in line: 1.72 + key, value = line.split('=', 1) 1.73 + cache[key] = value 1.74 + for precious in PRECIOUS_VARS: 1.75 + entry = 'ac_cv_env_%s_value' % precious 1.76 + if entry in cache and (not precious in os.environ or os.environ[precious] != cache[entry]): 1.77 + os.remove('config.cache') 1.78 + return 1.79 + 1.80 + 1.81 +def dump(dump_file, shell): 1.82 + if os.path.exists('config.cache'): 1.83 + maybe_clear_cache() 1.84 + if not os.path.exists('config.status'): 1.85 + if os.path.exists(dump_file): 1.86 + os.remove(dump_file) 1.87 + return 1.88 + 1.89 + config_files = [File('config.status')] 1.90 + 1.91 + # Scan the config.status output for information about configuration files 1.92 + # it generates. 1.93 + config_status_output = subprocess.check_output( 1.94 + [shell, '-c', './config.status --help'], 1.95 + stderr=subprocess.STDOUT).splitlines() 1.96 + state = None 1.97 + for line in config_status_output: 1.98 + if line.startswith('Configuration') and line.endswith(':'): 1.99 + state = 'config' 1.100 + elif not line.startswith(' '): 1.101 + state = None 1.102 + elif state == 'config': 1.103 + for f in (couple.split(':')[0] for couple in line.split()): 1.104 + if os.path.isfile(f): 1.105 + config_files.append(File(f)) 1.106 + 1.107 + with open(dump_file, 'wb') as f: 1.108 + pickle.dump(config_files, f) 1.109 + 1.110 + 1.111 +def adjust(dump_file, configure): 1.112 + if not os.path.exists(dump_file): 1.113 + return 1.114 + 1.115 + config_files = [] 1.116 + 1.117 + try: 1.118 + with open(dump_file, 'rb') as f: 1.119 + config_files = pickle.load(f) 1.120 + except Exception: 1.121 + pass 1.122 + 1.123 + for f in config_files: 1.124 + # Still touch config.status if configure is newer than its original 1.125 + # mtime. 1.126 + if configure and os.path.basename(f.path) == 'config.status' and \ 1.127 + os.path.getmtime(configure) > f.mtime: 1.128 + continue 1.129 + f.update_time() 1.130 + 1.131 + os.remove(dump_file) 1.132 + 1.133 + 1.134 +CONFIG_DUMP = 'config_files.pkl' 1.135 + 1.136 +if __name__ == '__main__': 1.137 + if sys.argv[1] == 'dump': 1.138 + dump(CONFIG_DUMP, sys.argv[2]) 1.139 + elif sys.argv[1] == 'adjust': 1.140 + adjust(CONFIG_DUMP, sys.argv[2] if len(sys.argv) > 2 else None)