bootstrap.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #!/usr/bin/env python
  2. import argparse
  3. import os
  4. import subprocess
  5. import sys
  6. from lib.config import LIBCHROMIUMCONTENT_COMMIT, BASE_URL, PLATFORM, \
  7. enable_verbose_mode, is_verbose_mode, get_target_arch
  8. from lib.util import execute_stdout, get_electron_version, scoped_cwd
  9. SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
  10. VENDOR_DIR = os.path.join(SOURCE_ROOT, 'vendor')
  11. PYTHON_26_URL = 'https://chromium.googlesource.com/chromium/deps/python_26'
  12. NPM = 'npm'
  13. if sys.platform in ['win32', 'cygwin']:
  14. NPM += '.cmd'
  15. def main():
  16. os.chdir(SOURCE_ROOT)
  17. args = parse_args()
  18. defines = args_to_defines(args)
  19. if not args.yes and PLATFORM != 'win32':
  20. check_root()
  21. if args.verbose:
  22. enable_verbose_mode()
  23. if sys.platform == 'cygwin':
  24. update_win32_python()
  25. update_submodules()
  26. libcc_source_path = args.libcc_source_path
  27. libcc_shared_library_path = args.libcc_shared_library_path
  28. libcc_static_library_path = args.libcc_static_library_path
  29. # Redirect to use local libchromiumcontent build.
  30. if args.build_libchromiumcontent:
  31. build_libchromiumcontent(args.verbose, args.target_arch, defines)
  32. dist_dir = os.path.join(SOURCE_ROOT, 'vendor', 'brightray', 'vendor',
  33. 'libchromiumcontent', 'dist', 'main')
  34. libcc_source_path = os.path.join(dist_dir, 'src')
  35. libcc_shared_library_path = os.path.join(dist_dir, 'shared_library')
  36. libcc_static_library_path = os.path.join(dist_dir, 'static_library')
  37. if PLATFORM != 'win32':
  38. if not args.disable_clang and args.clang_dir == '':
  39. # Download prebuilt clang binaries.
  40. update_clang()
  41. setup_python_libs()
  42. update_node_modules('.')
  43. bootstrap_brightray(args.dev, args.url, args.target_arch,
  44. libcc_source_path, libcc_shared_library_path,
  45. libcc_static_library_path)
  46. if PLATFORM == 'linux':
  47. download_sysroot(args.target_arch)
  48. create_chrome_version_h()
  49. touch_config_gypi()
  50. run_update(defines, args.msvs)
  51. update_electron_modules('spec', args.target_arch)
  52. def parse_args():
  53. parser = argparse.ArgumentParser(description='Bootstrap this project')
  54. parser.add_argument('-u', '--url',
  55. help='The base URL from which to download '
  56. 'libchromiumcontent (i.e., the URL you passed to '
  57. 'libchromiumcontent\'s script/upload script',
  58. default=BASE_URL,
  59. required=False)
  60. parser.add_argument('-v', '--verbose',
  61. action='store_true',
  62. help='Prints the output of the subprocesses')
  63. parser.add_argument('-d', '--dev', action='store_true',
  64. help='Do not download static_library build')
  65. parser.add_argument('-y', '--yes', '--assume-yes',
  66. action='store_true',
  67. help='Run non-interactively by assuming "yes" to all ' \
  68. 'prompts.')
  69. parser.add_argument('--msvs', action='store_true',
  70. help='Generate Visual Studio project')
  71. parser.add_argument('--target_arch', default=get_target_arch(),
  72. help='Manually specify the arch to build for')
  73. parser.add_argument('--clang_dir', default='', help='Path to clang binaries')
  74. parser.add_argument('--disable_clang', action='store_true',
  75. help='Use compilers other than clang for building')
  76. parser.add_argument('--build_libchromiumcontent', action='store_true',
  77. help='Build local version of libchromiumcontent')
  78. parser.add_argument('--libcc_source_path', required=False,
  79. help='The source path of libchromiumcontent. ' \
  80. 'NOTE: All options of libchromiumcontent are ' \
  81. 'required OR let electron choose it')
  82. parser.add_argument('--libcc_shared_library_path', required=False,
  83. help='The shared library path of libchromiumcontent.')
  84. parser.add_argument('--libcc_static_library_path', required=False,
  85. help='The static library path of libchromiumcontent.')
  86. parser.add_argument('--defines', default='',
  87. help='The build variables passed to gyp')
  88. return parser.parse_args()
  89. def args_to_defines(args):
  90. defines = args.defines
  91. if args.disable_clang:
  92. defines += ' clang=0'
  93. if args.clang_dir:
  94. defines += ' make_clang_dir=' + args.clang_dir
  95. defines += ' clang_use_chrome_plugins=0'
  96. return defines
  97. def check_root():
  98. if os.geteuid() == 0:
  99. print "We suggest not running this as root, unless you're really sure."
  100. choice = raw_input("Do you want to continue? [y/N]: ")
  101. if choice not in ('y', 'Y'):
  102. sys.exit(0)
  103. def update_submodules():
  104. execute_stdout(['git', 'submodule', 'sync', '--recursive'])
  105. execute_stdout(['git', 'submodule', 'update', '--init', '--recursive'])
  106. def setup_python_libs():
  107. for lib in ('requests', 'boto'):
  108. with scoped_cwd(os.path.join(VENDOR_DIR, lib)):
  109. execute_stdout([sys.executable, 'setup.py', 'build'])
  110. def bootstrap_brightray(is_dev, url, target_arch, libcc_source_path,
  111. libcc_shared_library_path,
  112. libcc_static_library_path):
  113. bootstrap = os.path.join(VENDOR_DIR, 'brightray', 'script', 'bootstrap')
  114. args = [
  115. '--commit', LIBCHROMIUMCONTENT_COMMIT,
  116. '--target_arch', target_arch,
  117. url
  118. ]
  119. if is_dev:
  120. args = ['--dev'] + args
  121. if (libcc_source_path != None and
  122. libcc_shared_library_path != None and
  123. libcc_static_library_path != None):
  124. args += ['--libcc_source_path', libcc_source_path,
  125. '--libcc_shared_library_path', libcc_shared_library_path,
  126. '--libcc_static_library_path', libcc_static_library_path]
  127. execute_stdout([sys.executable, bootstrap] + args)
  128. def set_clang_env(env):
  129. llvm_dir = os.path.join(SOURCE_ROOT, 'vendor', 'llvm-build',
  130. 'Release+Asserts', 'bin')
  131. env['CC'] = os.path.join(llvm_dir, 'clang')
  132. env['CXX'] = os.path.join(llvm_dir, 'clang++')
  133. def update_node_modules(dirname, env=None):
  134. if env is None:
  135. env = os.environ.copy()
  136. if PLATFORM == 'linux':
  137. # Use prebuilt clang for building native modules.
  138. set_clang_env(env)
  139. env['npm_config_clang'] = '1'
  140. with scoped_cwd(dirname):
  141. args = [NPM, 'install']
  142. if is_verbose_mode():
  143. args += ['--verbose']
  144. # Ignore npm install errors when running in CI.
  145. if os.environ.has_key('CI'):
  146. try:
  147. execute_stdout(args, env)
  148. except subprocess.CalledProcessError:
  149. pass
  150. else:
  151. execute_stdout(args, env)
  152. def update_electron_modules(dirname, target_arch):
  153. env = os.environ.copy()
  154. env['npm_config_arch'] = target_arch
  155. env['npm_config_target'] = get_electron_version()
  156. env['npm_config_disturl'] = 'https://atom.io/download/electron'
  157. update_node_modules(dirname, env)
  158. def update_win32_python():
  159. with scoped_cwd(VENDOR_DIR):
  160. if not os.path.exists('python_26'):
  161. execute_stdout(['git', 'clone', PYTHON_26_URL])
  162. def build_libchromiumcontent(verbose, target_arch, defines):
  163. args = [sys.executable,
  164. os.path.join(SOURCE_ROOT, 'script', 'build-libchromiumcontent.py')]
  165. if verbose:
  166. args += ['-v']
  167. if defines:
  168. args += ['--defines', defines]
  169. execute_stdout(args + ['--target_arch', target_arch])
  170. def update_clang():
  171. execute_stdout([os.path.join(SOURCE_ROOT, 'script', 'update-clang.sh')])
  172. def download_sysroot(target_arch):
  173. if target_arch == 'ia32':
  174. target_arch = 'i386'
  175. if target_arch == 'x64':
  176. target_arch = 'amd64'
  177. execute_stdout([sys.executable,
  178. os.path.join(SOURCE_ROOT, 'script', 'install-sysroot.py'),
  179. '--arch', target_arch])
  180. def create_chrome_version_h():
  181. version_file = os.path.join(SOURCE_ROOT, 'vendor', 'brightray', 'vendor',
  182. 'libchromiumcontent', 'VERSION')
  183. target_file = os.path.join(SOURCE_ROOT, 'atom', 'common', 'chrome_version.h')
  184. template_file = os.path.join(SOURCE_ROOT, 'script', 'chrome_version.h.in')
  185. with open(version_file, 'r') as f:
  186. version = f.read()
  187. with open(template_file, 'r') as f:
  188. template = f.read()
  189. content = template.replace('{PLACEHOLDER}', version.strip())
  190. # We update the file only if the content has changed (ignoring line ending
  191. # differences).
  192. should_write = True
  193. if os.path.isfile(target_file):
  194. with open(target_file, 'r') as f:
  195. should_write = f.read().replace('r', '') != content.replace('r', '')
  196. if should_write:
  197. with open(target_file, 'w') as f:
  198. f.write(content)
  199. def touch_config_gypi():
  200. config_gypi = os.path.join(SOURCE_ROOT, 'vendor', 'node', 'config.gypi')
  201. with open(config_gypi, 'w+') as f:
  202. content = "\n{'variables':{}}"
  203. if f.read() != content:
  204. f.write(content)
  205. def run_update(defines, msvs):
  206. args = [sys.executable, os.path.join(SOURCE_ROOT, 'script', 'update.py')]
  207. if defines:
  208. args += ['--defines', defines]
  209. if msvs:
  210. args += ['--msvs']
  211. execute_stdout(args)
  212. if __name__ == '__main__':
  213. sys.exit(main())