| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 4 # for details. All rights reserved. Use of this source code is governed by a | 4 # for details. All rights reserved. Use of this source code is governed by a |
| 5 # BSD-style license that can be found in the LICENSE file. | 5 # BSD-style license that can be found in the LICENSE file. |
| 6 # | |
| 7 | 6 |
| 8 import optparse | 7 # This script simply forwards to tools/ninja.py. It is retained simply to avoid |
| 9 import os | 8 # breaking various workflows. |
| 10 import re | 9 |
| 11 import shutil | 10 import ninja |
| 12 import subprocess | |
| 13 import sys | 11 import sys |
| 14 import time | |
| 15 import utils | |
| 16 | |
| 17 HOST_OS = utils.GuessOS() | |
| 18 HOST_ARCH = utils.GuessArchitecture() | |
| 19 HOST_CPUS = utils.GuessCpus() | |
| 20 SCRIPT_DIR = os.path.dirname(sys.argv[0]) | |
| 21 DART_ROOT = os.path.realpath(os.path.join(SCRIPT_DIR, '..')) | |
| 22 THIRD_PARTY_ROOT = os.path.join(DART_ROOT, 'third_party') | |
| 23 | |
| 24 arm_cc_error = """ | |
| 25 Couldn't find the arm cross compiler. | |
| 26 To make sure that you have the arm cross compilation tools installed, run: | |
| 27 | |
| 28 $ wget http://src.chromium.org/chrome/trunk/src/build/install-build-deps.sh | |
| 29 OR | |
| 30 $ svn co http://src.chromium.org/chrome/trunk/src/build; cd build | |
| 31 Then, | |
| 32 $ chmod u+x install-build-deps.sh | |
| 33 $ ./install-build-deps.sh --arm --no-chromeos-fonts | |
| 34 """ | |
| 35 DEFAULT_ARM_CROSS_COMPILER_PATH = '/usr/bin' | |
| 36 | |
| 37 usage = """\ | |
| 38 usage: %%prog [options] [targets] | |
| 39 | |
| 40 This script runs 'make' in the *current* directory. So, run it from | |
| 41 the Dart repo root, | |
| 42 | |
| 43 %s , | |
| 44 | |
| 45 unless you really intend to use a non-default Makefile.""" % DART_ROOT | |
| 46 | |
| 47 DART_USE_GYP = "DART_USE_GYP" | |
| 48 | |
| 49 | |
| 50 def use_gyp(): | |
| 51 return DART_USE_GYP in os.environ | |
| 52 | |
| 53 | |
| 54 def BuildOptions(): | |
| 55 result = optparse.OptionParser(usage=usage) | |
| 56 result.add_option("-m", "--mode", | |
| 57 help='Build variants (comma-separated).', | |
| 58 metavar='[all,debug,release,product]', | |
| 59 default='debug') | |
| 60 result.add_option("-v", "--verbose", | |
| 61 help='Verbose output.', | |
| 62 default=False, action="store_true") | |
| 63 result.add_option("-a", "--arch", | |
| 64 help='Target architectures (comma-separated).', | |
| 65 metavar='[all,ia32,x64,simarm,arm,simarmv6,armv6,simarmv5te,armv5te,' | |
| 66 'simarm64,arm64,simdbc,armsimdbc]', | |
| 67 default=utils.GuessArchitecture()) | |
| 68 result.add_option("--os", | |
| 69 help='Target OSs (comma-separated).', | |
| 70 metavar='[all,host,android]', | |
| 71 default='host') | |
| 72 result.add_option("-t", "--toolchain", | |
| 73 help='Cross-compiler toolchain path', | |
| 74 default=None) | |
| 75 result.add_option("-j", | |
| 76 help='The number of parallel jobs to run.', | |
| 77 metavar=HOST_CPUS, | |
| 78 default=str(HOST_CPUS)) | |
| 79 (vs_directory, vs_executable) = utils.GuessVisualStudioPath() | |
| 80 result.add_option("--devenv", | |
| 81 help='Path containing devenv.com on Windows', | |
| 82 default=vs_directory) | |
| 83 result.add_option("--executable", | |
| 84 help='Name of the devenv.com/msbuild executable on Windows (varies for ' | |
| 85 'different versions of Visual Studio)', | |
| 86 default=vs_executable) | |
| 87 result.add_option("--gyp", | |
| 88 help='Build with gyp.', | |
| 89 default=use_gyp(), | |
| 90 action='store_true') | |
| 91 return result | |
| 92 | |
| 93 | |
| 94 def ProcessOsOption(os_name): | |
| 95 if os_name == 'host': | |
| 96 return HOST_OS | |
| 97 return os_name | |
| 98 | |
| 99 | |
| 100 def ProcessOptions(options, args): | |
| 101 if options.arch == 'all': | |
| 102 options.arch = 'ia32,x64,simarm,simarm64,simdbc64' | |
| 103 if options.mode == 'all': | |
| 104 options.mode = 'debug,release,product' | |
| 105 if options.os == 'all': | |
| 106 options.os = 'host,android' | |
| 107 options.mode = options.mode.split(',') | |
| 108 options.arch = options.arch.split(',') | |
| 109 options.os = options.os.split(',') | |
| 110 if not options.gyp and options.toolchain != None: | |
| 111 print "The --toolchain flag is only supported by the gyp build." | |
| 112 print "When using the GN build, set the toolchain and sysroot using gn.py." | |
| 113 return False | |
| 114 for mode in options.mode: | |
| 115 if not mode in ['debug', 'release', 'product']: | |
| 116 print "Unknown mode %s" % mode | |
| 117 return False | |
| 118 for arch in options.arch: | |
| 119 archs = ['ia32', 'x64', 'simarm', 'arm', 'simarmv6', 'armv6', | |
| 120 'simarmv5te', 'armv5te', 'simarm64', 'arm64', | |
| 121 'simdbc', 'simdbc64', 'armsimdbc', 'armsimdbc64'] | |
| 122 if not arch in archs: | |
| 123 print "Unknown arch %s" % arch | |
| 124 return False | |
| 125 options.os = [ProcessOsOption(os_name) for os_name in options.os] | |
| 126 for os_name in options.os: | |
| 127 if not os_name in ['android', 'freebsd', 'linux', 'macos', 'win32']: | |
| 128 print "Unknown os %s" % os_name | |
| 129 return False | |
| 130 if os_name != HOST_OS: | |
| 131 if os_name != 'android': | |
| 132 print "Unsupported target os %s" % os_name | |
| 133 return False | |
| 134 if not HOST_OS in ['linux', 'macos']: | |
| 135 print ("Cross-compilation to %s is not supported on host os %s." | |
| 136 % (os_name, HOST_OS)) | |
| 137 return False | |
| 138 if not arch in ['ia32', 'x64', 'arm', 'armv6', 'armv5te', 'arm64', | |
| 139 'simdbc', 'simdbc64']: | |
| 140 print ("Cross-compilation to %s is not supported for architecture %s." | |
| 141 % (os_name, arch)) | |
| 142 return False | |
| 143 # We have not yet tweaked the v8 dart build to work with the Android | |
| 144 # NDK/SDK, so don't try to build it. | |
| 145 if not args: | |
| 146 print "For android builds you must specify a target, such as 'runtime'." | |
| 147 return False | |
| 148 return True | |
| 149 | |
| 150 | |
| 151 def GetToolchainPrefix(target_os, arch, options): | |
| 152 if options.toolchain != None: | |
| 153 return options.toolchain | |
| 154 | |
| 155 if target_os == 'android': | |
| 156 android_toolchain = GetAndroidToolchainDir(HOST_OS, arch) | |
| 157 if arch == 'arm' or arch == 'simdbc': | |
| 158 return os.path.join(android_toolchain, 'arm-linux-androideabi') | |
| 159 if arch == 'arm64' or arch == 'simdbc64': | |
| 160 return os.path.join(android_toolchain, 'aarch64-linux-android') | |
| 161 if arch == 'ia32': | |
| 162 return os.path.join(android_toolchain, 'i686-linux-android') | |
| 163 if arch == 'x64': | |
| 164 return os.path.join(android_toolchain, 'x86_64-linux-android') | |
| 165 | |
| 166 # If no cross compiler is specified, only try to figure one out on Linux. | |
| 167 if not HOST_OS in ['linux']: | |
| 168 raise Exception('Unless --toolchain is used cross-building is only ' | |
| 169 'supported on Linux.') | |
| 170 | |
| 171 # For ARM Linux, by default use the Linux distribution's cross-compiler. | |
| 172 if arch == 'arm' or arch == 'armsimdbc': | |
| 173 # To use a non-hf compiler, specify on the command line with --toolchain. | |
| 174 return (DEFAULT_ARM_CROSS_COMPILER_PATH + "/arm-linux-gnueabihf") | |
| 175 if arch == 'arm64': | |
| 176 return (DEFAULT_ARM_CROSS_COMPILER_PATH + "/aarch64-linux-gnu") | |
| 177 | |
| 178 return None | |
| 179 | |
| 180 | |
| 181 def SetTools(arch, target_os, options): | |
| 182 toolsOverride = None | |
| 183 | |
| 184 toolchainprefix = GetToolchainPrefix(target_os, arch, options) | |
| 185 | |
| 186 # Override the Android toolchain's linker to handle some complexity in the | |
| 187 # linker arguments that gyp has trouble with. | |
| 188 linker = "" | |
| 189 if target_os == 'android': | |
| 190 linker = os.path.join(DART_ROOT, 'tools', 'android_link.py') | |
| 191 elif toolchainprefix: | |
| 192 linker = toolchainprefix + "-g++" | |
| 193 | |
| 194 if toolchainprefix: | |
| 195 toolsOverride = { | |
| 196 "CC.target" : toolchainprefix + "-gcc", | |
| 197 "CXX.target" : toolchainprefix + "-g++", | |
| 198 "AR.target" : toolchainprefix + "-ar", | |
| 199 "LINK.target": linker, | |
| 200 "NM.target" : toolchainprefix + "-nm", | |
| 201 } | |
| 202 return toolsOverride | |
| 203 | |
| 204 | |
| 205 def CheckDirExists(path, docstring): | |
| 206 if not os.path.isdir(path): | |
| 207 raise Exception('Could not find %s directory %s' | |
| 208 % (docstring, path)) | |
| 209 | |
| 210 | |
| 211 def GetAndroidToolchainDir(host_os, target_arch): | |
| 212 global THIRD_PARTY_ROOT | |
| 213 if host_os not in ['linux']: | |
| 214 raise Exception('Unsupported host os %s' % host_os) | |
| 215 if target_arch not in ['ia32', 'x64', 'arm', 'arm64', 'simdbc', 'simdbc64']: | |
| 216 raise Exception('Unsupported target architecture %s' % target_arch) | |
| 217 | |
| 218 # Set up path to the Android NDK. | |
| 219 CheckDirExists(THIRD_PARTY_ROOT, 'third party tools') | |
| 220 android_tools = os.path.join(THIRD_PARTY_ROOT, 'android_tools') | |
| 221 CheckDirExists(android_tools, 'Android tools') | |
| 222 android_ndk_root = os.path.join(android_tools, 'ndk') | |
| 223 CheckDirExists(android_ndk_root, 'Android NDK') | |
| 224 | |
| 225 # Set up the directory of the Android NDK cross-compiler toolchain. | |
| 226 toolchain_arch = 'arm-linux-androideabi-4.9' | |
| 227 if target_arch == 'arm64' or target_arch == 'simdbc64': | |
| 228 toolchain_arch = 'aarch64-linux-android-4.9' | |
| 229 if target_arch == 'ia32': | |
| 230 toolchain_arch = 'x86-4.9' | |
| 231 if target_arch == 'x64': | |
| 232 toolchain_arch = 'x86_64-4.9' | |
| 233 toolchain_dir = 'linux-x86_64' | |
| 234 android_toolchain = os.path.join(android_ndk_root, | |
| 235 'toolchains', toolchain_arch, | |
| 236 'prebuilt', toolchain_dir, 'bin') | |
| 237 CheckDirExists(android_toolchain, 'Android toolchain') | |
| 238 | |
| 239 return android_toolchain | |
| 240 | |
| 241 | |
| 242 def Execute(args): | |
| 243 process = subprocess.Popen(args) | |
| 244 process.wait() | |
| 245 if process.returncode != 0: | |
| 246 raise Exception(args[0] + " failed") | |
| 247 | |
| 248 | |
| 249 def CurrentDirectoryBaseName(): | |
| 250 """Returns the name of the current directory""" | |
| 251 return os.path.relpath(os.curdir, start=os.pardir) | |
| 252 | |
| 253 | |
| 254 def FilterEmptyXcodebuildSections(process): | |
| 255 """ | |
| 256 Filter output from xcodebuild so empty sections are less verbose. | |
| 257 | |
| 258 The output from xcodebuild looks like this: | |
| 259 | |
| 260 Build settings from command line: | |
| 261 SYMROOT = .../xcodebuild | |
| 262 | |
| 263 === BUILD TARGET samples OF PROJECT dart WITH CONFIGURATION ... | |
| 264 | |
| 265 Check dependencies | |
| 266 | |
| 267 === BUILD AGGREGATE TARGET upload_sdk OF PROJECT dart WITH CONFIGURATION ... | |
| 268 | |
| 269 Check dependencies | |
| 270 | |
| 271 PhaseScriptExecution "Action \"upload_sdk_py\"" xcodebuild/dart.build/... | |
| 272 cd ... | |
| 273 /bin/sh -c .../xcodebuild/dart.build/ReleaseIA32/upload_sdk.build/... | |
| 274 | |
| 275 | |
| 276 ** BUILD SUCCEEDED ** | |
| 277 | |
| 278 """ | |
| 279 | |
| 280 def is_empty_chunk(input): | |
| 281 empty_chunk = ['', 'Check dependencies', ''] | |
| 282 return not input or (len(input) == 4 and input[1:] == empty_chunk) | |
| 283 | |
| 284 def unbuffered(callable): | |
| 285 # Use iter to disable buffering in for-in. | |
| 286 return iter(callable, '') | |
| 287 | |
| 288 section = None | |
| 289 chunk = [] | |
| 290 # Is stdout a terminal which supports colors? | |
| 291 is_fancy_tty = False | |
| 292 clr_eol = None | |
| 293 if sys.stdout.isatty(): | |
| 294 term = os.getenv('TERM', 'dumb') | |
| 295 # The capability "clr_eol" means clear the line from cursor to end | |
| 296 # of line. See man pages for tput and terminfo. | |
| 297 try: | |
| 298 with open('/dev/null', 'a') as dev_null: | |
| 299 clr_eol = subprocess.check_output(['tput', '-T' + term, 'el'], | |
| 300 stderr=dev_null) | |
| 301 if clr_eol: | |
| 302 is_fancy_tty = True | |
| 303 except subprocess.CalledProcessError: | |
| 304 is_fancy_tty = False | |
| 305 except AttributeError: | |
| 306 is_fancy_tty = False | |
| 307 pattern = re.compile(r'=== BUILD.* TARGET (.*) OF PROJECT (.*) WITH ' + | |
| 308 r'CONFIGURATION (.*) ===') | |
| 309 has_interesting_info = False | |
| 310 for line in unbuffered(process.stdout.readline): | |
| 311 line = line.rstrip() | |
| 312 if line.startswith('=== BUILD ') or line.startswith('** BUILD '): | |
| 313 has_interesting_info = False | |
| 314 section = line | |
| 315 if is_fancy_tty: | |
| 316 match = re.match(pattern, section) | |
| 317 if match: | |
| 318 section = '%s/%s/%s' % ( | |
| 319 match.group(3), match.group(2), match.group(1)) | |
| 320 # Truncate to avoid extending beyond 80 columns. | |
| 321 section = section[:80] | |
| 322 # If stdout is a terminal, emit "progress" information. The | |
| 323 # progress information is the first line of the current chunk. | |
| 324 # After printing the line, move the cursor back to the | |
| 325 # beginning of the line. This has two effects: First, if the | |
| 326 # chunk isn't empty, the first line will be overwritten | |
| 327 # (avoiding duplication). Second, the next segment line will | |
| 328 # overwrite it too avoid long scrollback. clr_eol ensures | |
| 329 # that there is no trailing garbage when a shorter line | |
| 330 # overwrites a longer line. | |
| 331 print '%s%s\r' % (clr_eol, section), | |
| 332 chunk = [] | |
| 333 if not section or has_interesting_info: | |
| 334 print line | |
| 335 else: | |
| 336 length = len(chunk) | |
| 337 if length == 2 and line != 'Check dependencies': | |
| 338 has_interesting_info = True | |
| 339 elif (length == 1 or length == 3) and line: | |
| 340 has_interesting_info = True | |
| 341 elif length > 3: | |
| 342 has_interesting_info = True | |
| 343 if has_interesting_info: | |
| 344 print '\n'.join(chunk) | |
| 345 chunk = [] | |
| 346 else: | |
| 347 chunk.append(line) | |
| 348 if not is_empty_chunk(chunk): | |
| 349 print '\n'.join(chunk) | |
| 350 | |
| 351 | |
| 352 def NotifyBuildDone(build_config, success, start): | |
| 353 if not success: | |
| 354 print "BUILD FAILED" | |
| 355 | |
| 356 sys.stdout.flush() | |
| 357 | |
| 358 # Display a notification if build time exceeded DART_BUILD_NOTIFICATION_DELAY. | |
| 359 notification_delay = float( | |
| 360 os.getenv('DART_BUILD_NOTIFICATION_DELAY', sys.float_info.max)) | |
| 361 if (time.time() - start) < notification_delay: | |
| 362 return | |
| 363 | |
| 364 if success: | |
| 365 message = 'Build succeeded.' | |
| 366 else: | |
| 367 message = 'Build failed.' | |
| 368 title = build_config | |
| 369 | |
| 370 command = None | |
| 371 if HOST_OS == 'macos': | |
| 372 # Use AppleScript to display a UI non-modal notification. | |
| 373 script = 'display notification "%s" with title "%s" sound name "Glass"' % ( | |
| 374 message, title) | |
| 375 command = "osascript -e '%s' &" % script | |
| 376 elif HOST_OS == 'linux': | |
| 377 if success: | |
| 378 icon = 'dialog-information' | |
| 379 else: | |
| 380 icon = 'dialog-error' | |
| 381 command = "notify-send -i '%s' '%s' '%s' &" % (icon, message, title) | |
| 382 elif HOST_OS == 'win32': | |
| 383 if success: | |
| 384 icon = 'info' | |
| 385 else: | |
| 386 icon = 'error' | |
| 387 command = ("powershell -command \"" | |
| 388 "[reflection.assembly]::loadwithpartialname('System.Windows.Forms')" | |
| 389 "| Out-Null;" | |
| 390 "[reflection.assembly]::loadwithpartialname('System.Drawing')" | |
| 391 "| Out-Null;" | |
| 392 "$n = new-object system.windows.forms.notifyicon;" | |
| 393 "$n.icon = [system.drawing.systemicons]::information;" | |
| 394 "$n.visible = $true;" | |
| 395 "$n.showballoontip(%d, '%s', '%s', " | |
| 396 "[system.windows.forms.tooltipicon]::%s);\"") % ( | |
| 397 5000, # Notification stays on for this many milliseconds | |
| 398 message, title, icon) | |
| 399 | |
| 400 if command: | |
| 401 # Ignore return code, if this command fails, it doesn't matter. | |
| 402 os.system(command) | |
| 403 | |
| 404 | |
| 405 def RunGN(target_os, mode, arch): | |
| 406 gn_os = 'host' if target_os == HOST_OS else target_os | |
| 407 gn_command = [ | |
| 408 'python', | |
| 409 os.path.join(DART_ROOT, 'tools', 'gn.py'), | |
| 410 '-m', mode, | |
| 411 '-a', arch, | |
| 412 '--os', gn_os, | |
| 413 '-v', | |
| 414 ] | |
| 415 process = subprocess.Popen(gn_command) | |
| 416 process.wait() | |
| 417 if process.returncode != 0: | |
| 418 print ("Tried to run GN, but it failed. Try running it manually: \n\t$ " + | |
| 419 ' '.join(gn_command)) | |
| 420 | |
| 421 | |
| 422 def ShouldRunGN(out_dir): | |
| 423 return (not os.path.exists(out_dir) or | |
| 424 not os.path.isfile(os.path.join(out_dir, 'args.gn'))) | |
| 425 | |
| 426 | |
| 427 def UseGoma(out_dir): | |
| 428 args_gn = os.path.join(out_dir, 'args.gn') | |
| 429 return 'use_goma = true' in open(args_gn, 'r').read() | |
| 430 | |
| 431 | |
| 432 # Try to start goma, but don't bail out if we can't. Instead print an error | |
| 433 # message, and let the build fail with its own error messages as well. | |
| 434 def EnsureGomaStarted(out_dir): | |
| 435 args_gn_path = os.path.join(out_dir, 'args.gn') | |
| 436 goma_dir = None | |
| 437 with open(args_gn_path, 'r') as fp: | |
| 438 for line in fp: | |
| 439 if 'goma_dir' in line: | |
| 440 words = line.split() | |
| 441 goma_dir = words[2][1:-1] # goma_dir = "/path/to/goma" | |
| 442 if not goma_dir: | |
| 443 print 'Could not find goma for ' + out_dir | |
| 444 return False | |
| 445 if not os.path.exists(goma_dir) or not os.path.isdir(goma_dir): | |
| 446 print 'Could not find goma at ' + goma_dir | |
| 447 return False | |
| 448 goma_ctl = os.path.join(goma_dir, 'goma_ctl.py') | |
| 449 goma_ctl_command = [ | |
| 450 'python', | |
| 451 goma_ctl, | |
| 452 'ensure_start', | |
| 453 ] | |
| 454 process = subprocess.Popen(goma_ctl_command) | |
| 455 process.wait() | |
| 456 if process.returncode != 0: | |
| 457 print ("Tried to run goma_ctl.py, but it failed. Try running it manually: " | |
| 458 + "\n\t" + ' '.join(goma_ctl_command)) | |
| 459 return False | |
| 460 return True | |
| 461 | |
| 462 | |
| 463 | |
| 464 def BuildNinjaCommand(options, target, target_os, mode, arch): | |
| 465 out_dir = utils.GetBuildRoot(HOST_OS, mode, arch, target_os) | |
| 466 if ShouldRunGN(out_dir): | |
| 467 RunGN(target_os, mode, arch) | |
| 468 command = ['ninja', '-C', out_dir] | |
| 469 if options.verbose: | |
| 470 command += ['-v'] | |
| 471 if UseGoma(out_dir): | |
| 472 if EnsureGomaStarted(out_dir): | |
| 473 command += ['-j1000'] | |
| 474 else: | |
| 475 # If we couldn't ensure that goma is started, let the build start, but | |
| 476 # slowly so we can see any helpful error messages that pop out. | |
| 477 command += ['-j1'] | |
| 478 command += [target] | |
| 479 return command | |
| 480 | |
| 481 | |
| 482 filter_xcodebuild_output = False | |
| 483 def BuildOneConfig(options, target, target_os, mode, arch): | |
| 484 global filter_xcodebuild_output | |
| 485 start_time = time.time() | |
| 486 args = [] | |
| 487 build_config = utils.GetBuildConf(mode, arch, target_os) | |
| 488 if not options.gyp: | |
| 489 args = BuildNinjaCommand(options, target, target_os, mode, arch) | |
| 490 else: | |
| 491 os.environ['DART_BUILD_MODE'] = mode | |
| 492 if HOST_OS == 'macos': | |
| 493 filter_xcodebuild_output = True | |
| 494 project_file = 'dart.xcodeproj' | |
| 495 if os.path.exists('dart-%s.gyp' % CurrentDirectoryBaseName()): | |
| 496 project_file = 'dart-%s.xcodeproj' % CurrentDirectoryBaseName() | |
| 497 if target == 'all': | |
| 498 target = 'All' | |
| 499 args = ['xcodebuild', | |
| 500 '-project', | |
| 501 project_file, | |
| 502 '-target', | |
| 503 target, | |
| 504 '-configuration', | |
| 505 build_config, | |
| 506 'SYMROOT=%s' % os.path.abspath('xcodebuild') | |
| 507 ] | |
| 508 elif HOST_OS == 'win32': | |
| 509 project_file = 'dart.sln' | |
| 510 if os.path.exists('dart-%s.gyp' % CurrentDirectoryBaseName()): | |
| 511 project_file = 'dart-%s.sln' % CurrentDirectoryBaseName() | |
| 512 # Select a platform suffix to pass to devenv. | |
| 513 if arch == 'ia32': | |
| 514 platform_suffix = 'Win32' | |
| 515 elif arch == 'x64': | |
| 516 platform_suffix = 'x64' | |
| 517 else: | |
| 518 print 'Unsupported arch for MSVC build: %s' % arch | |
| 519 return 1 | |
| 520 config_name = '%s|%s' % (build_config, platform_suffix) | |
| 521 if target == 'all': | |
| 522 args = [options.devenv + os.sep + options.executable, | |
| 523 '/build', | |
| 524 config_name, | |
| 525 project_file | |
| 526 ] | |
| 527 else: | |
| 528 args = [options.devenv + os.sep + options.executable, | |
| 529 '/build', | |
| 530 config_name, | |
| 531 '/project', | |
| 532 target, | |
| 533 project_file | |
| 534 ] | |
| 535 else: | |
| 536 make = 'make' | |
| 537 if HOST_OS == 'freebsd': | |
| 538 make = 'gmake' | |
| 539 # work around lack of flock | |
| 540 os.environ['LINK'] = '$(CXX)' | |
| 541 args = [make, | |
| 542 '-j', | |
| 543 options.j, | |
| 544 'BUILDTYPE=' + build_config, | |
| 545 ] | |
| 546 if target_os != HOST_OS: | |
| 547 args += ['builddir_name=' + utils.GetBuildDir(HOST_OS)] | |
| 548 if options.verbose: | |
| 549 args += ['V=1'] | |
| 550 | |
| 551 args += [target] | |
| 552 | |
| 553 toolsOverride = None | |
| 554 if override_tools: | |
| 555 toolsOverride = SetTools(arch, target_os, options) | |
| 556 if toolsOverride: | |
| 557 for k, v in toolsOverride.iteritems(): | |
| 558 args.append( k + "=" + v) | |
| 559 if options.verbose: | |
| 560 print k + " = " + v | |
| 561 if not os.path.isfile(toolsOverride['CC.target']): | |
| 562 if arch == 'arm': | |
| 563 print arm_cc_error | |
| 564 else: | |
| 565 print "Couldn't find compiler: %s" % toolsOverride['CC.target'] | |
| 566 return 1 | |
| 567 | |
| 568 print ' '.join(args) | |
| 569 process = None | |
| 570 if filter_xcodebuild_output: | |
| 571 process = subprocess.Popen(args, | |
| 572 stdin=None, | |
| 573 bufsize=1, # Line buffered. | |
| 574 stdout=subprocess.PIPE, | |
| 575 stderr=subprocess.STDOUT) | |
| 576 FilterEmptyXcodebuildSections(process) | |
| 577 else: | |
| 578 process = subprocess.Popen(args, stdin=None) | |
| 579 process.wait() | |
| 580 if process.returncode != 0: | |
| 581 NotifyBuildDone(build_config, success=False, start=start_time) | |
| 582 return 1 | |
| 583 else: | |
| 584 NotifyBuildDone(build_config, success=True, start=start_time) | |
| 585 | |
| 586 return 0 | |
| 587 | |
| 588 | |
| 589 def Main(): | |
| 590 utils.ConfigureJava() | |
| 591 # Parse the options. | |
| 592 parser = BuildOptions() | |
| 593 (options, args) = parser.parse_args() | |
| 594 if not ProcessOptions(options, args): | |
| 595 parser.print_help() | |
| 596 return 1 | |
| 597 # Determine which targets to build. By default we build the "all" target. | |
| 598 if len(args) == 0: | |
| 599 targets = ['all'] | |
| 600 else: | |
| 601 targets = args | |
| 602 | |
| 603 # Build all targets for each requested configuration. | |
| 604 for target in targets: | |
| 605 for target_os in options.os: | |
| 606 for mode in options.mode: | |
| 607 for arch in options.arch: | |
| 608 if BuildOneConfig(options, target, target_os, | |
| 609 mode, arch) != 0: | |
| 610 return 1 | |
| 611 | |
| 612 return 0 | |
| 613 | |
| 614 | 12 |
| 615 if __name__ == '__main__': | 13 if __name__ == '__main__': |
| 616 sys.exit(Main()) | 14 sys.exit(ninja.Main()) |
| OLD | NEW |