build-all.py 10 KB

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