blob: 4789af7a3f97b61bc321cb6a565b99085ae7f796 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001#! /usr/bin/env python
2
Adrian Alexei32b75ee2013-02-28 11:01:49 -08003# Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are met:
7# * Redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer.
9# * Redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution.
Duy Truong790f06d2013-02-13 16:38:12 -080012# * Neither the name of The Linux Foundation nor
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070013# the names of its contributors may be used to endorse or promote
14# products derived from this software without specific prior written
15# permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29# Build the kernel for all targets using the Android build environment.
30#
31# TODO: Accept arguments to indicate what to build.
32
33import glob
34from optparse import OptionParser
35import subprocess
36import os
37import os.path
Andrew Walkerfc0606c2012-10-23 18:43:11 -070038import re
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039import shutil
40import sys
41
42version = 'build-all.py, version 0.01'
43
44build_dir = '../all-kernels'
David Brown8e881292012-08-23 11:17:01 -070045make_command = ["vmlinux", "modules", "dtbs"]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046make_env = os.environ
47make_env.update({
48 'ARCH': 'arm',
49 'CROSS_COMPILE': 'arm-none-linux-gnueabi-',
50 'KCONFIG_NOTIMESTAMP': 'true' })
51all_options = {}
52
53def error(msg):
54 sys.stderr.write("error: %s\n" % msg)
55
56def fail(msg):
57 """Fail with a user-printed message"""
58 error(msg)
59 sys.exit(1)
60
61def check_kernel():
62 """Ensure that PWD is a kernel directory"""
63 if (not os.path.isfile('MAINTAINERS') or
64 not os.path.isfile('arch/arm/mach-msm/Kconfig')):
65 fail("This doesn't seem to be an MSM kernel dir")
66
67def check_build():
68 """Ensure that the build directory is present."""
69 if not os.path.isdir(build_dir):
70 try:
71 os.makedirs(build_dir)
72 except OSError as exc:
73 if exc.errno == errno.EEXIST:
74 pass
75 else:
76 raise
77
78def update_config(file, str):
79 print 'Updating %s with \'%s\'\n' % (file, str)
80 defconfig = open(file, 'a')
81 defconfig.write(str + '\n')
82 defconfig.close()
83
84def scan_configs():
85 """Get the full list of defconfigs appropriate for this tree."""
86 names = {}
Andrew Walkerfc0606c2012-10-23 18:43:11 -070087 arch_pats = (
88 r'[fm]sm[0-9]*_defconfig',
89 r'apq*_defconfig',
90 r'qsd*_defconfig',
Andrew Walkerfc0606c2012-10-23 18:43:11 -070091 )
92 for p in arch_pats:
93 for n in glob.glob('arch/arm/configs/' + p):
94 names[os.path.basename(n)[:-10]] = n
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070095 return names
96
97class Builder:
98 def __init__(self, logname):
99 self.logname = logname
100 self.fd = open(logname, 'w')
101
102 def run(self, args):
103 devnull = open('/dev/null', 'r')
104 proc = subprocess.Popen(args, stdin=devnull,
105 env=make_env,
106 bufsize=0,
107 stdout=subprocess.PIPE,
108 stderr=subprocess.STDOUT)
109 count = 0
110 # for line in proc.stdout:
111 rawfd = proc.stdout.fileno()
112 while True:
113 line = os.read(rawfd, 1024)
114 if not line:
115 break
116 self.fd.write(line)
117 self.fd.flush()
118 if all_options.verbose:
119 sys.stdout.write(line)
120 sys.stdout.flush()
121 else:
122 for i in range(line.count('\n')):
123 count += 1
124 if count == 64:
125 count = 0
126 print
127 sys.stdout.write('.')
128 sys.stdout.flush()
129 print
130 result = proc.wait()
131
132 self.fd.close()
133 return result
134
135failed_targets = []
136
137def build(target):
138 dest_dir = os.path.join(build_dir, target)
139 log_name = '%s/log-%s.log' % (build_dir, target)
140 print 'Building %s in %s log %s' % (target, dest_dir, log_name)
141 if not os.path.isdir(dest_dir):
142 os.mkdir(dest_dir)
143 defconfig = 'arch/arm/configs/%s_defconfig' % target
144 dotconfig = '%s/.config' % dest_dir
145 savedefconfig = '%s/defconfig' % dest_dir
146 shutil.copyfile(defconfig, dotconfig)
147
Andrew Walkerfc0606c2012-10-23 18:43:11 -0700148 staging_dir = 'install_staging'
149 modi_dir = '%s' % staging_dir
150 hdri_dir = '%s/usr' % staging_dir
151 shutil.rmtree(os.path.join(dest_dir, staging_dir), ignore_errors=True)
152
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 devnull = open('/dev/null', 'r')
154 subprocess.check_call(['make', 'O=%s' % dest_dir,
155 '%s_defconfig' % target], env=make_env, stdin=devnull)
156 devnull.close()
157
158 if not all_options.updateconfigs:
Andrew Walkerfc0606c2012-10-23 18:43:11 -0700159 # Build targets can be dependent upon the completion of previous
160 # build targets, so build them one at a time.
161 cmd_line = ['make',
162 'INSTALL_HDR_PATH=%s' % hdri_dir,
163 'INSTALL_MOD_PATH=%s' % modi_dir,
164 'O=%s' % dest_dir]
165 build_targets = []
166 for c in make_command:
167 if re.match(r'^-{1,2}\w', c):
168 cmd_line.append(c)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700169 else:
Andrew Walkerfc0606c2012-10-23 18:43:11 -0700170 build_targets.append(c)
171 for t in build_targets:
172 build = Builder(log_name)
173
174 result = build.run(cmd_line + [t])
175 if result != 0:
176 if all_options.keep_going:
177 failed_targets.append(target)
178 fail_or_error = error
179 else:
180 fail_or_error = fail
181 fail_or_error("Failed to build %s, see %s" %
182 (target, build.logname))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183
184 # Copy the defconfig back.
185 if all_options.configs or all_options.updateconfigs:
186 devnull = open('/dev/null', 'r')
187 subprocess.check_call(['make', 'O=%s' % dest_dir,
188 'savedefconfig'], env=make_env, stdin=devnull)
189 devnull.close()
190 shutil.copyfile(savedefconfig, defconfig)
191
192def build_many(allconf, targets):
193 print "Building %d target(s)" % len(targets)
194 for target in targets:
195 if all_options.updateconfigs:
196 update_config(allconf[target], all_options.updateconfigs)
197 build(target)
198 if failed_targets:
199 fail('\n '.join(["Failed targets:"] +
200 [target for target in failed_targets]))
201
202def main():
203 global make_command
204
205 check_kernel()
206 check_build()
207
208 configs = scan_configs()
209
210 usage = ("""
211 %prog [options] all -- Build all targets
212 %prog [options] target target ... -- List specific targets
213 %prog [options] perf -- Build all perf targets
214 %prog [options] noperf -- Build all non-perf targets""")
215 parser = OptionParser(usage=usage, version=version)
216 parser.add_option('--configs', action='store_true',
217 dest='configs',
218 help="Copy configs back into tree")
219 parser.add_option('--list', action='store_true',
220 dest='list',
221 help='List available targets')
222 parser.add_option('-v', '--verbose', action='store_true',
223 dest='verbose',
224 help='Output to stdout in addition to log file')
225 parser.add_option('--oldconfig', action='store_true',
226 dest='oldconfig',
227 help='Only process "make oldconfig"')
228 parser.add_option('--updateconfigs',
229 dest='updateconfigs',
230 help="Update defconfigs with provided option setting, "
231 "e.g. --updateconfigs=\'CONFIG_USE_THING=y\'")
232 parser.add_option('-j', '--jobs', type='int', dest="jobs",
233 help="Number of simultaneous jobs")
234 parser.add_option('-l', '--load-average', type='int',
235 dest='load_average',
236 help="Don't start multiple jobs unless load is below LOAD_AVERAGE")
237 parser.add_option('-k', '--keep-going', action='store_true',
238 dest='keep_going', default=False,
239 help="Keep building other targets if a target fails")
240 parser.add_option('-m', '--make-target', action='append',
241 help='Build the indicated make target (default: %s)' %
242 ' '.join(make_command))
243
244 (options, args) = parser.parse_args()
245 global all_options
246 all_options = options
247
248 if options.list:
249 print "Available targets:"
250 for target in configs.keys():
251 print " %s" % target
252 sys.exit(0)
253
254 if options.oldconfig:
255 make_command = ["oldconfig"]
256 elif options.make_target:
257 make_command = options.make_target
258
259 if options.jobs:
260 make_command.append("-j%d" % options.jobs)
261 if options.load_average:
262 make_command.append("-l%d" % options.load_average)
263
264 if args == ['all']:
265 build_many(configs, configs.keys())
266 elif args == ['perf']:
267 targets = []
268 for t in configs.keys():
269 if "perf" in t:
270 targets.append(t)
271 build_many(configs, targets)
272 elif args == ['noperf']:
273 targets = []
274 for t in configs.keys():
275 if "perf" not in t:
276 targets.append(t)
277 build_many(configs, targets)
278 elif len(args) > 0:
279 targets = []
280 for t in args:
281 if t not in configs.keys():
282 parser.error("Target '%s' not one of %s" % (t, configs.keys()))
283 targets.append(t)
284 build_many(configs, targets)
285 else:
286 parser.error("Must specify a target to build, or 'all'")
287
288if __name__ == "__main__":
289 main()