bootstrap.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #!/usr/bin/env python
  2. import argparse
  3. import errno
  4. import os
  5. import re
  6. import subprocess
  7. import sys
  8. from lib.config import BASE_URL, PLATFORM, MIPS64EL_SYSROOT_URL, \
  9. MIPS64EL_GCC, MIPS64EL_GCC_URL, enable_verbose_mode, \
  10. is_verbose_mode, get_target_arch
  11. from lib.util import execute, execute_stdout, get_electron_version, \
  12. scoped_cwd, download, update_node_modules
  13. SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
  14. VENDOR_DIR = os.path.join(SOURCE_ROOT, 'vendor')
  15. DOWNLOAD_DIR = os.path.join(VENDOR_DIR, 'download')
  16. PYTHON_26_URL = 'https://chromium.googlesource.com/chromium/deps/python_26'
  17. def main():
  18. os.chdir(SOURCE_ROOT)
  19. args = parse_args()
  20. defines = args_to_defines(args)
  21. if not args.yes and PLATFORM != 'win32':
  22. check_root()
  23. if args.verbose:
  24. enable_verbose_mode()
  25. if sys.platform == 'cygwin':
  26. update_win32_python()
  27. update_submodules()
  28. libcc_source_path = args.libcc_source_path
  29. libcc_shared_library_path = args.libcc_shared_library_path
  30. libcc_static_library_path = args.libcc_static_library_path
  31. if args.target_arch == 'mips64el':
  32. download_mips64el_toolchain()
  33. if args.target_arch.startswith('arm'):
  34. download_native_mksnapshot(args.target_arch)
  35. # Redirect to use local libchromiumcontent build.
  36. if args.build_release_libcc or args.build_debug_libcc:
  37. build_libchromiumcontent(args.verbose, args.target_arch, defines,
  38. args.build_debug_libcc, args.update_libcc)
  39. dist_dir = os.path.join(VENDOR_DIR, 'libchromiumcontent', 'dist', 'main')
  40. libcc_source_path = os.path.join(dist_dir, 'src')
  41. libcc_shared_library_path = os.path.join(dist_dir, 'shared_library')
  42. libcc_static_library_path = os.path.join(dist_dir, 'static_library')
  43. if PLATFORM != 'win32':
  44. if not args.disable_clang and args.clang_dir == '':
  45. # Download prebuilt clang binaries.
  46. update_clang()
  47. setup_python_libs()
  48. update_node_modules('.')
  49. setup_libchromiumcontent(args.dev, args.target_arch, args.url,
  50. libcc_source_path, libcc_shared_library_path,
  51. libcc_static_library_path)
  52. if PLATFORM == 'linux' and args.target_arch != 'mips64el':
  53. download_sysroot(args.target_arch)
  54. create_chrome_version_h()
  55. touch_config_gypi()
  56. run_update(defines, args.msvs)
  57. def parse_args():
  58. parser = argparse.ArgumentParser(description='Bootstrap this project')
  59. parser.add_argument('-u', '--url',
  60. help='The base URL from which to download '
  61. 'libchromiumcontent (i.e., the URL you passed to '
  62. 'libchromiumcontent\'s script/upload script',
  63. default=BASE_URL,
  64. required=False)
  65. parser.add_argument('-v', '--verbose',
  66. action='store_true',
  67. help='Prints the output of the subprocesses')
  68. parser.add_argument('-d', '--dev', action='store_true',
  69. help='Do not download static_library build')
  70. parser.add_argument('-y', '--yes', '--assume-yes',
  71. action='store_true',
  72. help='Run non-interactively by assuming "yes" to all ' \
  73. 'prompts.')
  74. parser.add_argument('--msvs', action='store_true',
  75. help='Generate Visual Studio project')
  76. parser.add_argument('--target_arch', default=get_target_arch(),
  77. help='Manually specify the arch to build for')
  78. parser.add_argument('--clang_dir', default='', help='Path to clang binaries')
  79. parser.add_argument('--disable_clang', action='store_true',
  80. help='Use compilers other than clang for building')
  81. build_libcc = parser.add_mutually_exclusive_group()
  82. build_libcc.add_argument('--build_release_libcc', action='store_true',
  83. help='Build release version of libchromiumcontent')
  84. build_libcc.add_argument('--build_debug_libcc', action='store_true',
  85. help='Build debug version of libchromiumcontent')
  86. parser.add_argument('--update_libcc', default=False,
  87. action='store_true', help=('force gclient invocation to '
  88. 'update libchromiumcontent'))
  89. parser.add_argument('--libcc_source_path', required=False,
  90. help='The source path of libchromiumcontent. ' \
  91. 'NOTE: All options of libchromiumcontent are ' \
  92. 'required OR let electron choose it')
  93. parser.add_argument('--libcc_shared_library_path', required=False,
  94. help='The shared library path of libchromiumcontent.')
  95. parser.add_argument('--libcc_static_library_path', required=False,
  96. help='The static library path of libchromiumcontent.')
  97. parser.add_argument('--defines', default='',
  98. help='The build variables passed to gyp')
  99. parser.add_argument('--cc_wrapper',
  100. help='Sets cc_wrapper for build. E.g. $(which sccache)')
  101. return parser.parse_args()
  102. def args_to_defines(args):
  103. defines = args.defines
  104. if args.disable_clang:
  105. defines += ' clang=0'
  106. if args.clang_dir:
  107. defines += ' make_clang_dir=' + args.clang_dir
  108. defines += ' clang_use_chrome_plugins=0'
  109. if args.cc_wrapper is not None:
  110. defines += ' cc_wrapper=' + args.cc_wrapper
  111. return defines
  112. def check_root():
  113. if os.geteuid() == 0:
  114. print "We suggest not running this as root, unless you're really sure."
  115. choice = raw_input("Do you want to continue? [y/N]: ")
  116. if choice not in ('y', 'Y'):
  117. sys.exit(0)
  118. def update_submodules():
  119. execute_stdout(['git', 'submodule', 'sync', '--recursive'])
  120. execute_stdout(['git', 'submodule', 'update', '--init', '--recursive'])
  121. def setup_python_libs():
  122. for lib in ('requests', 'boto'):
  123. with scoped_cwd(os.path.join(VENDOR_DIR, lib)):
  124. execute_stdout([sys.executable, 'setup.py', 'build'])
  125. def setup_libchromiumcontent(is_dev, target_arch, url,
  126. libcc_source_path,
  127. libcc_shared_library_path,
  128. libcc_static_library_path):
  129. target_dir = os.path.join(DOWNLOAD_DIR, 'libchromiumcontent')
  130. script = os.path.join(VENDOR_DIR, 'libchromiumcontent', 'script',
  131. 'download')
  132. args = ['-f', '-c', get_libchromiumcontent_commit(), '--target_arch',
  133. target_arch, url, target_dir]
  134. if (libcc_source_path != None and
  135. libcc_shared_library_path != None and
  136. libcc_static_library_path != None):
  137. args += ['--libcc_source_path', libcc_source_path,
  138. '--libcc_shared_library_path', libcc_shared_library_path,
  139. '--libcc_static_library_path', libcc_static_library_path]
  140. mkdir_p(target_dir)
  141. else:
  142. mkdir_p(DOWNLOAD_DIR)
  143. if is_dev:
  144. subprocess.check_call([sys.executable, script] + args)
  145. else:
  146. subprocess.check_call([sys.executable, script, '-s'] + args)
  147. def update_win32_python():
  148. with scoped_cwd(VENDOR_DIR):
  149. if not os.path.exists('python_26'):
  150. execute_stdout(['git', 'clone', PYTHON_26_URL])
  151. def build_libchromiumcontent(verbose, target_arch, defines, debug,
  152. force_update):
  153. args = [sys.executable,
  154. os.path.join(SOURCE_ROOT, 'script', 'build-libchromiumcontent.py')]
  155. if debug:
  156. args += ['-d']
  157. if force_update:
  158. args += ['--force-update']
  159. if verbose:
  160. args += ['-v']
  161. if defines:
  162. args += ['--defines', defines]
  163. execute_stdout(args + ['--target_arch', target_arch])
  164. def update_clang():
  165. execute_stdout([os.path.join(SOURCE_ROOT, 'script', 'update-clang.sh')])
  166. def download_sysroot(target_arch):
  167. if target_arch == 'ia32':
  168. target_arch = 'i386'
  169. if target_arch == 'x64':
  170. target_arch = 'amd64'
  171. execute_stdout([sys.executable,
  172. os.path.join(SOURCE_ROOT, 'script', 'install-sysroot.py'),
  173. '--arch', target_arch],
  174. cwd=VENDOR_DIR)
  175. def download_mips64el_toolchain():
  176. # Download sysroot image.
  177. if not os.path.exists(os.path.join(VENDOR_DIR,
  178. 'debian_jessie_mips64-sysroot')):
  179. tar_name = 'debian_jessie_mips64-sysroot.tar.bz2'
  180. download(tar_name, MIPS64EL_SYSROOT_URL,
  181. os.path.join(SOURCE_ROOT, tar_name))
  182. subprocess.call(['tar', '-jxf', tar_name, '-C', VENDOR_DIR])
  183. os.remove(tar_name)
  184. # Download toolchain.
  185. if not os.path.exists(os.path.join(VENDOR_DIR, MIPS64EL_GCC)):
  186. tar_name = MIPS64EL_GCC + '.tar.gz'
  187. download(tar_name, MIPS64EL_GCC_URL, os.path.join(SOURCE_ROOT, tar_name))
  188. subprocess.check_call(['tar', '-xf', tar_name, '-C', VENDOR_DIR])
  189. os.remove(tar_name)
  190. def download_native_mksnapshot(arch):
  191. if not os.path.exists(os.path.join(VENDOR_DIR,
  192. 'native_mksnapshot')):
  193. tar_name = 'native-mksnapshot.tar.bz2'
  194. url = '{0}/linux/{1}/{2}/{3}'.format(BASE_URL, arch,
  195. get_libchromiumcontent_commit(), tar_name)
  196. download(tar_name, url, os.path.join(SOURCE_ROOT, tar_name))
  197. subprocess.call(['tar', '-jxf', tar_name, '-C', VENDOR_DIR])
  198. os.remove(tar_name)
  199. def create_chrome_version_h():
  200. version_file = os.path.join(VENDOR_DIR, 'libchromiumcontent', 'VERSION')
  201. target_file = os.path.join(SOURCE_ROOT, 'atom', 'common', 'chrome_version.h')
  202. template_file = os.path.join(SOURCE_ROOT, 'script', 'chrome_version.h.in')
  203. with open(version_file, 'r') as f:
  204. version = f.read()
  205. with open(template_file, 'r') as f:
  206. template = f.read()
  207. content = template.replace('{PLACEHOLDER}', version.strip())
  208. # We update the file only if the content has changed (ignoring line ending
  209. # differences).
  210. should_write = True
  211. if os.path.isfile(target_file):
  212. with open(target_file, 'r') as f:
  213. should_write = f.read().replace('r', '') != content.replace('r', '')
  214. if should_write:
  215. with open(target_file, 'w') as f:
  216. f.write(content)
  217. def touch_config_gypi():
  218. config_gypi = os.path.join(SOURCE_ROOT, 'vendor', 'node', 'config.gypi')
  219. with open(config_gypi, 'w+') as f:
  220. content = "\n{'variables':{}}"
  221. if f.read() != content:
  222. f.write(content)
  223. def run_update(defines, msvs):
  224. args = [sys.executable, os.path.join(SOURCE_ROOT, 'script', 'update.py')]
  225. if defines:
  226. args += ['--defines', defines]
  227. if msvs:
  228. args += ['--msvs']
  229. execute_stdout(args)
  230. def get_libchromiumcontent_commit():
  231. commit = os.getenv('LIBCHROMIUMCONTENT_COMMIT')
  232. if commit:
  233. return commit
  234. # Extract full SHA-1 of libcc submodule commit
  235. output = execute(['git', 'submodule', 'status', 'vendor/libchromiumcontent'])
  236. commit = re.split('^(?:\s*)([a-f0-9]{40})(?:\s+)', output)[1]
  237. return commit
  238. def mkdir_p(path):
  239. try:
  240. os.makedirs(path)
  241. except OSError as e:
  242. if e.errno != errno.EEXIST:
  243. raise
  244. if __name__ == '__main__':
  245. sys.exit(main())