build/subconfigure.py

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:b34c17be2b09
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/.
4
5 # This script is used to capture the content of config.status-generated
6 # files and subsequently restore their timestamp if they haven't changed.
7
8 import os
9 import re
10 import subprocess
11 import sys
12 import pickle
13
14 class File(object):
15 def __init__(self, path):
16 self._path = path
17 self._content = open(path, 'rb').read()
18 stat = os.stat(path)
19 self._times = (stat.st_atime, stat.st_mtime)
20
21 @property
22 def path(self):
23 return self._path
24
25 @property
26 def mtime(self):
27 return self._times[1]
28
29 def update_time(self):
30 '''If the file hasn't changed since the instance was created,
31 restore its old modification time.'''
32 if not os.path.exists(self._path):
33 return
34 if open(self._path, 'rb').read() == self._content:
35 os.utime(self._path, self._times)
36
37
38 # As defined in the various sub-configures in the tree
39 PRECIOUS_VARS = set([
40 'build_alias',
41 'host_alias',
42 'target_alias',
43 'CC',
44 'CFLAGS',
45 'LDFLAGS',
46 'LIBS',
47 'CPPFLAGS',
48 'CPP',
49 'CCC',
50 'CXXFLAGS',
51 'CXX',
52 'CCASFLAGS',
53 'CCAS',
54 ])
55
56
57 # Autoconf, in some of the sub-configures used in the tree, likes to error
58 # out when "precious" variables change in value. The solution it gives to
59 # straighten things is to either run make distclean or remove config.cache.
60 # There's no reason not to do the latter automatically instead of failing,
61 # doing the cleanup (which, on buildbots means a full clobber), and
62 # restarting from scratch.
63 def maybe_clear_cache():
64 comment = re.compile(r'^\s+#')
65 cache = {}
66 with open('config.cache') as f:
67 for line in f.readlines():
68 if not comment.match(line) and '=' in line:
69 key, value = line.split('=', 1)
70 cache[key] = value
71 for precious in PRECIOUS_VARS:
72 entry = 'ac_cv_env_%s_value' % precious
73 if entry in cache and (not precious in os.environ or os.environ[precious] != cache[entry]):
74 os.remove('config.cache')
75 return
76
77
78 def dump(dump_file, shell):
79 if os.path.exists('config.cache'):
80 maybe_clear_cache()
81 if not os.path.exists('config.status'):
82 if os.path.exists(dump_file):
83 os.remove(dump_file)
84 return
85
86 config_files = [File('config.status')]
87
88 # Scan the config.status output for information about configuration files
89 # it generates.
90 config_status_output = subprocess.check_output(
91 [shell, '-c', './config.status --help'],
92 stderr=subprocess.STDOUT).splitlines()
93 state = None
94 for line in config_status_output:
95 if line.startswith('Configuration') and line.endswith(':'):
96 state = 'config'
97 elif not line.startswith(' '):
98 state = None
99 elif state == 'config':
100 for f in (couple.split(':')[0] for couple in line.split()):
101 if os.path.isfile(f):
102 config_files.append(File(f))
103
104 with open(dump_file, 'wb') as f:
105 pickle.dump(config_files, f)
106
107
108 def adjust(dump_file, configure):
109 if not os.path.exists(dump_file):
110 return
111
112 config_files = []
113
114 try:
115 with open(dump_file, 'rb') as f:
116 config_files = pickle.load(f)
117 except Exception:
118 pass
119
120 for f in config_files:
121 # Still touch config.status if configure is newer than its original
122 # mtime.
123 if configure and os.path.basename(f.path) == 'config.status' and \
124 os.path.getmtime(configure) > f.mtime:
125 continue
126 f.update_time()
127
128 os.remove(dump_file)
129
130
131 CONFIG_DUMP = 'config_files.pkl'
132
133 if __name__ == '__main__':
134 if sys.argv[1] == 'dump':
135 dump(CONFIG_DUMP, sys.argv[2])
136 elif sys.argv[1] == 'adjust':
137 adjust(CONFIG_DUMP, sys.argv[2] if len(sys.argv) > 2 else None)

mercurial