| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Windows can't run .sh files, so this is a Python implementation of | 6 """Windows can't run .sh files, so this is a Python implementation of |
| 7 update.sh. This script should replace update.sh on all platforms eventually.""" | 7 update.sh. This script should replace update.sh on all platforms eventually.""" |
| 8 | 8 |
| 9 import argparse |
| 9 import os | 10 import os |
| 10 import re | 11 import re |
| 11 import shutil | 12 import shutil |
| 12 import subprocess | 13 import subprocess |
| 13 import stat | 14 import stat |
| 14 import sys | 15 import sys |
| 15 import time | 16 import time |
| 16 | 17 |
| 17 # Do NOT CHANGE this if you don't know what you're doing -- see | 18 # Do NOT CHANGE this if you don't know what you're doing -- see |
| 18 # https://code.google.com/p/chromium/wiki/UpdatingClang | 19 # https://code.google.com/p/chromium/wiki/UpdatingClang |
| 19 # Reverting problematic clang rolls is safe, though. | 20 # Reverting problematic clang rolls is safe, though. |
| 20 # Note: this revision is only used for Windows. Other platforms use update.sh. | 21 # Note: this revision is only used for Windows. Other platforms use update.sh. |
| 21 LLVM_WIN_REVISION = 'HEAD' | 22 LLVM_WIN_REVISION = 'HEAD' |
| 22 | 23 |
| 23 # ASan on Windows is useful enough to use it even while the clang/win is still | 24 # ASan on Windows is useful enough to use it even while the clang/win is still |
| 24 # in bringup. Use a pinned revision to make it slightly more stable. | 25 # in bringup. Use a pinned revision to make it slightly more stable. |
| 25 if (re.search(r'\b(asan)=1', os.environ.get('GYP_DEFINES', '')) and | 26 if (re.search(r'\b(asan)=1', os.environ.get('GYP_DEFINES', '')) and |
| 26 not 'LLVM_FORCE_HEAD_REVISION' in os.environ): | 27 not 'LLVM_FORCE_HEAD_REVISION' in os.environ): |
| 27 LLVM_WIN_REVISION = '232554' | 28 LLVM_WIN_REVISION = '235793' |
| 28 | 29 |
| 29 # Path constants. (All of these should be absolute paths.) | 30 # Path constants. (All of these should be absolute paths.) |
| 30 THIS_DIR = os.path.abspath(os.path.dirname(__file__)) | 31 THIS_DIR = os.path.abspath(os.path.dirname(__file__)) |
| 31 CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..', '..')) | 32 CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..', '..')) |
| 32 LLVM_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm') | 33 LLVM_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm') |
| 34 CHROME_TOOLS_SHIM_DIR = os.path.join(LLVM_DIR, 'tools', 'chrometools') |
| 33 LLVM_BUILD_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm-build', | 35 LLVM_BUILD_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm-build', |
| 34 'Release+Asserts') | 36 'Release+Asserts') |
| 35 COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, '32bit-compiler-rt') | 37 COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, '32bit-compiler-rt') |
| 36 CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang') | 38 CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang') |
| 37 LLD_DIR = os.path.join(LLVM_DIR, 'tools', 'lld') | 39 LLD_DIR = os.path.join(LLVM_DIR, 'tools', 'lld') |
| 38 COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt') | 40 COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt') |
| 39 STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision') | 41 STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision') |
| 40 VERSION = '3.7.0' | 42 VERSION = '3.7.0' |
| 41 | 43 |
| 42 LLVM_REPO_URL='https://llvm.org/svn/llvm-project' | 44 LLVM_REPO_URL='https://llvm.org/svn/llvm-project' |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 return | 124 return |
| 123 | 125 |
| 124 if os.path.isdir(dir): | 126 if os.path.isdir(dir): |
| 125 print "Removing %s." % (dir) | 127 print "Removing %s." % (dir) |
| 126 RmTree(dir) | 128 RmTree(dir) |
| 127 | 129 |
| 128 print "Retrying." | 130 print "Retrying." |
| 129 RunCommand(command) | 131 RunCommand(command) |
| 130 | 132 |
| 131 | 133 |
| 134 def DeleteChromeToolsShim(): |
| 135 shutil.rmtree(CHROME_TOOLS_SHIM_DIR, ignore_errors=True) |
| 136 |
| 137 |
| 138 def CreateChromeToolsShim(): |
| 139 """Hooks the Chrome tools into the LLVM build. |
| 140 |
| 141 Several Chrome tools have dependencies on LLVM/Clang libraries. The LLVM build |
| 142 detects implicit tools in the tools subdirectory, so this helper install a |
| 143 shim CMakeLists.txt that forwards to the real directory for the Chrome tools. |
| 144 |
| 145 Note that the shim directory name intentionally has no - or _. The implicit |
| 146 tool detection logic munges them in a weird way.""" |
| 147 assert not any(i in os.path.basename(CHROME_TOOLS_SHIM_DIR) for i in '-_') |
| 148 os.mkdir(CHROME_TOOLS_SHIM_DIR) |
| 149 with file(os.path.join(CHROME_TOOLS_SHIM_DIR, 'CMakeLists.txt'), 'w') as f: |
| 150 f.write('# Automatically generated by tools/clang/scripts/update.py. ' + |
| 151 'Do not edit.\n') |
| 152 f.write('# Since tools/clang is located in another directory, use the \n') |
| 153 f.write('# two arg version to specify where build artifacts go. CMake\n') |
| 154 f.write('# disallows reuse of the same binary dir for multiple source\n') |
| 155 f.write('# dirs, so the build artifacts need to go into a subdirectory.\n') |
| 156 f.write('add_subdirectory(${CHROMIUM_TOOLS_SRC} ' + |
| 157 '${CMAKE_CURRENT_BINARY_DIR}/a)\n') |
| 158 |
| 159 |
| 132 def AddCMakeToPath(): | 160 def AddCMakeToPath(): |
| 133 """Look for CMake and add it to PATH if it's not there already.""" | 161 """Look for CMake and add it to PATH if it's not there already.""" |
| 134 try: | 162 try: |
| 135 # First check if cmake is already on PATH. | 163 # First check if cmake is already on PATH. |
| 136 subprocess.call(['cmake', '--version']) | 164 subprocess.call(['cmake', '--version']) |
| 137 return | 165 return |
| 138 except OSError as e: | 166 except OSError as e: |
| 139 if e.errno != os.errno.ENOENT: | 167 if e.errno != os.errno.ENOENT: |
| 140 raise | 168 raise |
| 141 | 169 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 # svn.bat in depot_tools will be ignored. | 202 # svn.bat in depot_tools will be ignored. |
| 175 default_pathext = ('.com', '.exe', '.bat', '.cmd') | 203 default_pathext = ('.com', '.exe', '.bat', '.cmd') |
| 176 for path in os.environ.get('PATH', '').split(os.pathsep): | 204 for path in os.environ.get('PATH', '').split(os.pathsep): |
| 177 for ext in default_pathext: | 205 for ext in default_pathext: |
| 178 candidate = os.path.join(path, 'svn' + ext) | 206 candidate = os.path.join(path, 'svn' + ext) |
| 179 if os.path.isfile(candidate): | 207 if os.path.isfile(candidate): |
| 180 return '-DSubversion_SVN_EXECUTABLE=%s' % candidate | 208 return '-DSubversion_SVN_EXECUTABLE=%s' % candidate |
| 181 return '' | 209 return '' |
| 182 | 210 |
| 183 | 211 |
| 184 def UpdateClang(): | 212 def UpdateClang(args): |
| 185 print 'Updating Clang to %s...' % (LLVM_WIN_REVISION) | 213 print 'Updating Clang to %s...' % (LLVM_WIN_REVISION) |
| 186 if LLVM_WIN_REVISION != 'HEAD' and ReadStampFile() == LLVM_WIN_REVISION: | 214 if LLVM_WIN_REVISION != 'HEAD' and ReadStampFile() == LLVM_WIN_REVISION: |
| 187 print 'Already up to date.' | 215 print 'Already up to date.' |
| 188 return 0 | 216 return 0 |
| 189 | 217 |
| 190 AddCMakeToPath() | 218 AddCMakeToPath() |
| 191 ClobberChromiumBuildFiles() | 219 if args.clobber: |
| 220 ClobberChromiumBuildFiles() |
| 192 | 221 |
| 193 # Reset the stamp file in case the build is unsuccessful. | 222 # Reset the stamp file in case the build is unsuccessful. |
| 194 WriteStampFile('') | 223 WriteStampFile('') |
| 195 | 224 |
| 225 DeleteChromeToolsShim(); |
| 196 Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR) | 226 Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR) |
| 197 Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR) | 227 Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR) |
| 198 Checkout('LLD', LLVM_REPO_URL + '/lld/trunk', LLD_DIR) | 228 Checkout('LLD', LLVM_REPO_URL + '/lld/trunk', LLD_DIR) |
| 199 Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR) | 229 Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR) |
| 230 CreateChromeToolsShim(); |
| 200 | 231 |
| 201 if not os.path.exists(LLVM_BUILD_DIR): | 232 if not os.path.exists(LLVM_BUILD_DIR): |
| 202 os.makedirs(LLVM_BUILD_DIR) | 233 os.makedirs(LLVM_BUILD_DIR) |
| 203 os.chdir(LLVM_BUILD_DIR) | 234 os.chdir(LLVM_BUILD_DIR) |
| 204 | 235 |
| 236 cmake_args = ['-GNinja', '-DCMAKE_BUILD_TYPE=Release', |
| 237 '-DLLVM_ENABLE_ASSERTIONS=ON', SubversionCmakeArg(), |
| 238 '-DCHROMIUM_TOOLS_SRC=%s' % os.path.join( |
| 239 CHROMIUM_DIR, 'tools', 'clang'), |
| 240 '-DCHROMIUM_TOOLS=%s' % ';'.join(args.tools)] |
| 241 |
| 205 RunCommand(GetVSVersion().SetupScript('x64') + | 242 RunCommand(GetVSVersion().SetupScript('x64') + |
| 206 ['&&', 'cmake', '-GNinja', '-DCMAKE_BUILD_TYPE=Release', | 243 ['&&', 'cmake'] + cmake_args + [LLVM_DIR]) |
| 207 '-DLLVM_ENABLE_ASSERTIONS=ON', SubversionCmakeArg(), LLVM_DIR]) | |
| 208 RunCommand(GetVSVersion().SetupScript('x64') + ['&&', 'ninja', 'all']) | 244 RunCommand(GetVSVersion().SetupScript('x64') + ['&&', 'ninja', 'all']) |
| 209 | 245 |
| 210 # Do an x86 build of compiler-rt to get the 32-bit ASan run-time. | 246 # Do an x86 build of compiler-rt to get the 32-bit ASan run-time. |
| 211 # TODO(hans): Remove once the regular build above produces this. | 247 # TODO(hans): Remove once the regular build above produces this. |
| 212 if not os.path.exists(COMPILER_RT_BUILD_DIR): | 248 if not os.path.exists(COMPILER_RT_BUILD_DIR): |
| 213 os.makedirs(COMPILER_RT_BUILD_DIR) | 249 os.makedirs(COMPILER_RT_BUILD_DIR) |
| 214 os.chdir(COMPILER_RT_BUILD_DIR) | 250 os.chdir(COMPILER_RT_BUILD_DIR) |
| 215 RunCommand(GetVSVersion().SetupScript('x86') + | 251 RunCommand(GetVSVersion().SetupScript('x86') + |
| 216 ['&&', 'cmake', '-GNinja', '-DCMAKE_BUILD_TYPE=Release', | 252 ['&&', 'cmake'] + cmake_args + [LLVM_DIR]) |
| 217 '-DLLVM_ENABLE_ASSERTIONS=ON', LLVM_DIR]) | |
| 218 RunCommand(GetVSVersion().SetupScript('x86') + ['&&', 'ninja', 'compiler-rt']) | 253 RunCommand(GetVSVersion().SetupScript('x86') + ['&&', 'ninja', 'compiler-rt']) |
| 219 | 254 |
| 220 # TODO(hans): Make this (and the .gypi and .isolate files) version number | 255 # TODO(hans): Make this (and the .gypi and .isolate files) version number |
| 221 # independent. | 256 # independent. |
| 222 asan_rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang', | 257 asan_rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang', |
| 223 VERSION, 'lib', 'windows') | 258 VERSION, 'lib', 'windows') |
| 224 asan_rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', | 259 asan_rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', |
| 225 VERSION, 'lib', 'windows') | 260 VERSION, 'lib', 'windows') |
| 226 CopyDirectoryContents(asan_rt_lib_src_dir, asan_rt_lib_dst_dir, | 261 CopyDirectoryContents(asan_rt_lib_src_dir, asan_rt_lib_dst_dir, |
| 227 r'^.*-i386\.lib$') | 262 r'^.*-i386\.lib$') |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 stderr=os.fdopen(os.dup(sys.stdin.fileno()))) | 304 stderr=os.fdopen(os.dup(sys.stdin.fileno()))) |
| 270 | 305 |
| 271 if not re.search(r'\b(clang|asan)=1', os.environ.get('GYP_DEFINES', '')): | 306 if not re.search(r'\b(clang|asan)=1', os.environ.get('GYP_DEFINES', '')): |
| 272 print 'Skipping Clang update (clang=1 was not set in GYP_DEFINES).' | 307 print 'Skipping Clang update (clang=1 was not set in GYP_DEFINES).' |
| 273 return 0 | 308 return 0 |
| 274 | 309 |
| 275 if re.search(r'\b(make_clang_dir)=', os.environ.get('GYP_DEFINES', '')): | 310 if re.search(r'\b(make_clang_dir)=', os.environ.get('GYP_DEFINES', '')): |
| 276 print 'Skipping Clang update (make_clang_dir= was set in GYP_DEFINES).' | 311 print 'Skipping Clang update (make_clang_dir= was set in GYP_DEFINES).' |
| 277 return 0 | 312 return 0 |
| 278 | 313 |
| 279 return UpdateClang() | 314 parser = argparse.ArgumentParser(description='Build Clang.') |
| 315 parser.add_argument('--no-clobber', dest='clobber', action='store_false') |
| 316 parser.add_argument('--tools', nargs='*', default=['plugins']) |
| 317 # For now, this flag is only used for the non-Windows flow, but argparser gets |
| 318 # mad if it sees a flag it doesn't recognize. |
| 319 parser.add_argument('--if-needed', action='store_true') |
| 320 return UpdateClang(parser.parse_args()) |
| 280 | 321 |
| 281 | 322 |
| 282 if __name__ == '__main__': | 323 if __name__ == '__main__': |
| 283 sys.exit(main()) | 324 sys.exit(main()) |
| OLD | NEW |