OLD | NEW |
---|---|
1 # Copyright (c) 2012 Google Inc. All rights reserved. | 1 # Copyright (c) 2012 Google Inc. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 from compiler.ast import Const | 5 from compiler.ast import Const |
6 from compiler.ast import Dict | 6 from compiler.ast import Dict |
7 from compiler.ast import Discard | 7 from compiler.ast import Discard |
8 from compiler.ast import List | 8 from compiler.ast import List |
9 from compiler.ast import Module | 9 from compiler.ast import Module |
10 from compiler.ast import Node | 10 from compiler.ast import Node |
11 from compiler.ast import Stmt | 11 from compiler.ast import Stmt |
12 import compiler | 12 import compiler |
13 import copy | 13 import copy |
14 import gyp.common | 14 import gyp.common |
15 import multiprocessing | |
15 import optparse | 16 import optparse |
16 import os.path | 17 import os.path |
17 import re | 18 import re |
18 import shlex | 19 import shlex |
19 import subprocess | 20 import subprocess |
20 import sys | 21 import sys |
22 import time | |
21 | 23 |
22 | 24 |
23 # A list of types that are treated as linkable. | 25 # A list of types that are treated as linkable. |
24 linkable_types = ['executable', 'shared_library', 'loadable_module'] | 26 linkable_types = ['executable', 'shared_library', 'loadable_module'] |
25 | 27 |
26 # A list of sections that contain links to other targets. | 28 # A list of sections that contain links to other targets. |
27 dependency_sections = ['dependencies', 'export_dependent_settings'] | 29 dependency_sections = ['dependencies', 'export_dependent_settings'] |
28 | 30 |
29 # base_path_sections is a list of sections defined by GYP that contain | 31 # base_path_sections is a list of sections defined by GYP that contain |
30 # pathnames. The generators can provide more keys, the two lists are merged | 32 # pathnames. The generators can provide more keys, the two lists are merged |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
322 for condition in data['conditions']: | 324 for condition in data['conditions']: |
323 if isinstance(condition, list): | 325 if isinstance(condition, list): |
324 for condition_dict in condition[1:]: | 326 for condition_dict in condition[1:]: |
325 ProcessToolsetsInDict(condition_dict) | 327 ProcessToolsetsInDict(condition_dict) |
326 | 328 |
327 | 329 |
328 # TODO(mark): I don't love this name. It just means that it's going to load | 330 # TODO(mark): I don't love this name. It just means that it's going to load |
329 # a build file that contains targets and is expected to provide a targets dict | 331 # a build file that contains targets and is expected to provide a targets dict |
330 # that contains the targets... | 332 # that contains the targets... |
331 def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes, | 333 def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes, |
332 depth, check): | 334 depth, check, load_dependencies): |
333 # If depth is set, predefine the DEPTH variable to be a relative path from | 335 # If depth is set, predefine the DEPTH variable to be a relative path from |
334 # this build file's directory to the directory identified by depth. | 336 # this build file's directory to the directory identified by depth. |
335 if depth: | 337 if depth: |
336 # TODO(dglazkov) The backslash/forward-slash replacement at the end is a | 338 # TODO(dglazkov) The backslash/forward-slash replacement at the end is a |
337 # temporary measure. This should really be addressed by keeping all paths | 339 # temporary measure. This should really be addressed by keeping all paths |
338 # in POSIX until actual project generation. | 340 # in POSIX until actual project generation. |
339 d = gyp.common.RelativePath(depth, os.path.dirname(build_file_path)) | 341 d = gyp.common.RelativePath(depth, os.path.dirname(build_file_path)) |
340 if d == '': | 342 if d == '': |
341 variables['DEPTH'] = '.' | 343 variables['DEPTH'] = '.' |
342 else: | 344 else: |
343 variables['DEPTH'] = d.replace('\\', '/') | 345 variables['DEPTH'] = d.replace('\\', '/') |
344 | 346 |
345 # If the generator needs absolue paths, then do so. | 347 # If the generator needs absolue paths, then do so. |
346 if absolute_build_file_paths: | 348 if absolute_build_file_paths: |
347 build_file_path = os.path.abspath(build_file_path) | 349 build_file_path = os.path.abspath(build_file_path) |
348 | 350 |
349 if build_file_path in data['target_build_files']: | 351 if build_file_path in data['target_build_files']: |
350 # Already loaded. | 352 # Already loaded. |
351 return | 353 return False |
352 data['target_build_files'].add(build_file_path) | 354 data['target_build_files'].add(build_file_path) |
353 | 355 |
354 gyp.DebugOutput(gyp.DEBUG_INCLUDES, | 356 gyp.DebugOutput(gyp.DEBUG_INCLUDES, |
355 "Loading Target Build File '%s'" % build_file_path) | 357 "Loading Target Build File '%s'" % build_file_path) |
356 | 358 |
357 build_file_data = LoadOneBuildFile(build_file_path, data, aux_data, variables, | 359 build_file_data = LoadOneBuildFile(build_file_path, data, aux_data, variables, |
358 includes, True, check) | 360 includes, True, check) |
359 | 361 |
360 # Store DEPTH for later use in generators. | 362 # Store DEPTH for later use in generators. |
361 build_file_data['_DEPTH'] = depth | 363 build_file_data['_DEPTH'] = depth |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
411 "Unable to find targets in build file %s" % build_file_path | 413 "Unable to find targets in build file %s" % build_file_path |
412 | 414 |
413 # No longer needed. | 415 # No longer needed. |
414 del build_file_data['target_defaults'] | 416 del build_file_data['target_defaults'] |
415 | 417 |
416 # Look for dependencies. This means that dependency resolution occurs | 418 # Look for dependencies. This means that dependency resolution occurs |
417 # after "pre" conditionals and variable expansion, but before "post" - | 419 # after "pre" conditionals and variable expansion, but before "post" - |
418 # in other words, you can't put a "dependencies" section inside a "post" | 420 # in other words, you can't put a "dependencies" section inside a "post" |
419 # conditional within a target. | 421 # conditional within a target. |
420 | 422 |
423 dependencies = [] | |
421 if 'targets' in build_file_data: | 424 if 'targets' in build_file_data: |
422 for target_dict in build_file_data['targets']: | 425 for target_dict in build_file_data['targets']: |
423 if 'dependencies' not in target_dict: | 426 if 'dependencies' not in target_dict: |
424 continue | 427 continue |
425 for dependency in target_dict['dependencies']: | 428 for dependency in target_dict['dependencies']: |
426 other_build_file = \ | 429 dependencies.append( |
427 gyp.common.ResolveTarget(build_file_path, dependency, None)[0] | 430 gyp.common.ResolveTarget(build_file_path, dependency, None)[0]) |
428 try: | |
429 LoadTargetBuildFile(other_build_file, data, aux_data, variables, | |
430 includes, depth, check) | |
431 except Exception, e: | |
432 gyp.common.ExceptionAppend( | |
433 e, 'while loading dependencies of %s' % build_file_path) | |
434 raise | |
435 | 431 |
436 return data | 432 if load_dependencies: |
433 for dependency in dependencies: | |
434 try: | |
435 LoadTargetBuildFile(dependency, data, aux_data, variables, | |
436 includes, depth, check, load_dependencies) | |
437 except Exception, e: | |
438 gyp.common.ExceptionAppend( | |
439 e, 'while loading dependencies of %s' % build_file_path) | |
440 raise | |
441 else: | |
442 return (build_file_path, dependencies) | |
443 | |
444 | |
445 # Wrapper around LoadTargetBuildFile used when LoadTargetBuildFile | |
446 # is executed in a worker process. | |
447 def CallLoadTargetBuildFile(global_flags, | |
448 build_file_path, data, | |
449 aux_data, variables, | |
450 includes, depth, check): | |
451 # Apply globals so that the worker process behaves the same. | |
452 for key, value in global_flags.iteritems(): | |
453 globals()[key] = value | |
454 | |
455 # Save the keys so we can return data that changed. | |
456 data_keys = set(data) | |
457 aux_data_keys = set(aux_data) | |
458 | |
459 result = LoadTargetBuildFile(build_file_path, data, | |
460 aux_data, variables, | |
461 includes, depth, check, False) | |
462 if not result: | |
463 return result | |
464 | |
465 (build_file_path, dependencies) = result | |
466 | |
467 data_out = {} | |
468 for key in data: | |
469 if key == 'target_build_files': | |
470 continue | |
471 if key not in data_keys: | |
472 data_out[key] = data[key] | |
473 aux_data_out = {} | |
474 for key in aux_data: | |
475 if key not in aux_data_keys: | |
476 aux_data_out[key] = aux_data[key] | |
477 | |
478 # This gets serialized and sent back to the main process via a pipe. | |
479 # It's handled in LoadTargetBuildFileCallback. | |
480 return (build_file_path, | |
481 data_out, | |
482 aux_data_out, | |
483 dependencies) | |
484 | |
485 | |
486 # Handle the results of LoadTargetBuildFile that executed in a separate | |
487 # process. | |
488 def LoadTargetBuildFileCallback(result): | |
489 (build_file_path0, data0, aux_data0, dependencies0) = result | |
490 gyp.data['target_build_files'].add(build_file_path0) | |
M-A Ruel
2012/09/18 19:42:18
Can you tell me where the "gyp" variable is define
dmazzoni
2012/09/19 21:14:52
gyp is the module object.
I cleaned this up by cr
| |
491 for key in data0: | |
492 gyp.data[key] = data0[key] | |
493 for key in aux_data0: | |
494 gyp.aux_data[key] = aux_data0[key] | |
495 for new_dependency in dependencies0: | |
496 if new_dependency not in gyp.scheduled: | |
497 gyp.scheduled.add(new_dependency) | |
498 gyp.dependencies.append(new_dependency) | |
499 gyp.pending -= 1 | |
500 | |
501 | |
502 def LoadTargetBuildFileParallel(build_file_path, data, aux_data, | |
503 variables, includes, depth, check): | |
504 gyp.dependencies = [build_file_path] | |
M-A Ruel
2012/09/18 19:42:18
I find the code a bit hard to read, the "gyp" vari
| |
505 gyp.scheduled = set([build_file_path]) | |
506 gyp.pending = 0 | |
507 gyp.data = data | |
508 gyp.aux_data = aux_data | |
509 while gyp.dependencies or gyp.pending: | |
510 if not gyp.dependencies: | |
511 time.sleep(0.003) | |
512 continue | |
513 | |
514 dependency = gyp.dependencies.pop() | |
515 | |
516 gyp.pending += 1 | |
517 data_in = {} | |
518 data_in['target_build_files'] = data['target_build_files'] | |
519 aux_data_in = {} | |
520 global_flags = { | |
521 'path_sections': globals()['path_sections'], | |
522 'non_configuration_keys': globals()['non_configuration_keys'], | |
523 'absolute_build_file_paths': globals()['absolute_build_file_paths'], | |
524 'multiple_toolsets': globals()['multiple_toolsets']} | |
525 | |
526 if 'pool' not in dir(gyp): | |
527 gyp.pool = multiprocessing.Pool(8) | |
528 gyp.pool.apply_async( | |
529 CallLoadTargetBuildFile, | |
530 args = (global_flags, dependency, | |
531 data_in, aux_data_in, | |
532 variables, includes, depth, check), | |
533 callback = LoadTargetBuildFileCallback) | |
534 time.sleep(0.003) | |
437 | 535 |
438 | 536 |
439 # Look for the bracket that matches the first bracket seen in a | 537 # Look for the bracket that matches the first bracket seen in a |
440 # string, and return the start and end as a tuple. For example, if | 538 # string, and return the start and end as a tuple. For example, if |
441 # the input is something like "<(foo <(bar)) blah", then it would | 539 # the input is something like "<(foo <(bar)) blah", then it would |
442 # return (1, 13), indicating the entire string except for the leading | 540 # return (1, 13), indicating the entire string except for the leading |
443 # "<" and trailing " blah". | 541 # "<" and trailing " blah". |
444 def FindEnclosingBracketGroup(input): | 542 def FindEnclosingBracketGroup(input): |
445 brackets = { '}': '{', | 543 brackets = { '}': '{', |
446 ']': '[', | 544 ']': '[', |
(...skipping 1879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2326 # Prepare a key like 'path/to:target_name'. | 2424 # Prepare a key like 'path/to:target_name'. |
2327 key = subdir + ':' + name | 2425 key = subdir + ':' + name |
2328 if key in used: | 2426 if key in used: |
2329 # Complain if this target is already used. | 2427 # Complain if this target is already used. |
2330 raise Exception('Duplicate target name "%s" in directory "%s" used both ' | 2428 raise Exception('Duplicate target name "%s" in directory "%s" used both ' |
2331 'in "%s" and "%s".' % (name, subdir, gyp, used[key])) | 2429 'in "%s" and "%s".' % (name, subdir, gyp, used[key])) |
2332 used[key] = gyp | 2430 used[key] = gyp |
2333 | 2431 |
2334 | 2432 |
2335 def Load(build_files, variables, includes, depth, generator_input_info, check, | 2433 def Load(build_files, variables, includes, depth, generator_input_info, check, |
2336 circular_check): | 2434 circular_check, parallel): |
2337 # Set up path_sections and non_configuration_keys with the default data plus | 2435 # Set up path_sections and non_configuration_keys with the default data plus |
2338 # the generator-specifc data. | 2436 # the generator-specifc data. |
2339 global path_sections | 2437 global path_sections |
2340 path_sections = base_path_sections[:] | 2438 path_sections = base_path_sections[:] |
2341 path_sections.extend(generator_input_info['path_sections']) | 2439 path_sections.extend(generator_input_info['path_sections']) |
2342 | 2440 |
2343 global non_configuration_keys | 2441 global non_configuration_keys |
2344 non_configuration_keys = base_non_configuration_keys[:] | 2442 non_configuration_keys = base_non_configuration_keys[:] |
2345 non_configuration_keys.extend(generator_input_info['non_configuration_keys']) | 2443 non_configuration_keys.extend(generator_input_info['non_configuration_keys']) |
2346 | 2444 |
(...skipping 20 matching lines...) Expand all Loading... | |
2367 # NOTE: data contains both "target" files (.gyp) and "includes" (.gypi), as | 2465 # NOTE: data contains both "target" files (.gyp) and "includes" (.gypi), as |
2368 # well as meta-data (e.g. 'included_files' key). 'target_build_files' keeps | 2466 # well as meta-data (e.g. 'included_files' key). 'target_build_files' keeps |
2369 # track of the keys corresponding to "target" files. | 2467 # track of the keys corresponding to "target" files. |
2370 data = {'target_build_files': set()} | 2468 data = {'target_build_files': set()} |
2371 aux_data = {} | 2469 aux_data = {} |
2372 for build_file in build_files: | 2470 for build_file in build_files: |
2373 # Normalize paths everywhere. This is important because paths will be | 2471 # Normalize paths everywhere. This is important because paths will be |
2374 # used as keys to the data dict and for references between input files. | 2472 # used as keys to the data dict and for references between input files. |
2375 build_file = os.path.normpath(build_file) | 2473 build_file = os.path.normpath(build_file) |
2376 try: | 2474 try: |
2377 LoadTargetBuildFile(build_file, data, aux_data, variables, includes, | 2475 if parallel: |
2378 depth, check) | 2476 print >>sys.stderr, 'Using parallel processing (experimental).' |
2477 LoadTargetBuildFileParallel(build_file, data, aux_data, | |
2478 variables, includes, depth, check) | |
2479 else: | |
2480 LoadTargetBuildFile(build_file, data, aux_data, | |
2481 variables, includes, depth, check, True) | |
2379 except Exception, e: | 2482 except Exception, e: |
2380 gyp.common.ExceptionAppend(e, 'while trying to load %s' % build_file) | 2483 gyp.common.ExceptionAppend(e, 'while trying to load %s' % build_file) |
2381 raise | 2484 raise |
2382 | 2485 |
2383 # Build a dict to access each target's subdict by qualified name. | 2486 # Build a dict to access each target's subdict by qualified name. |
2384 targets = BuildTargetsDict(data) | 2487 targets = BuildTargetsDict(data) |
2385 | 2488 |
2386 # Fully qualify all dependency links. | 2489 # Fully qualify all dependency links. |
2387 QualifyDependencies(targets) | 2490 QualifyDependencies(targets) |
2388 | 2491 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2476 ValidateRunAsInTarget(target, target_dict, build_file) | 2579 ValidateRunAsInTarget(target, target_dict, build_file) |
2477 ValidateActionsInTarget(target, target_dict, build_file) | 2580 ValidateActionsInTarget(target, target_dict, build_file) |
2478 | 2581 |
2479 # Generators might not expect ints. Turn them into strs. | 2582 # Generators might not expect ints. Turn them into strs. |
2480 TurnIntIntoStrInDict(data) | 2583 TurnIntIntoStrInDict(data) |
2481 | 2584 |
2482 # TODO(mark): Return |data| for now because the generator needs a list of | 2585 # TODO(mark): Return |data| for now because the generator needs a list of |
2483 # build files that came in. In the future, maybe it should just accept | 2586 # build files that came in. In the future, maybe it should just accept |
2484 # a list, and not the whole data dict. | 2587 # a list, and not the whole data dict. |
2485 return [flat_list, targets, data] | 2588 return [flat_list, targets, data] |
OLD | NEW |