Chromium Code Reviews| 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 """ | 5 """ |
| 6 This module helps emulate Visual Studio 2008 behavior on top of other | 6 This module helps emulate Visual Studio 2008 behavior on top of other |
| 7 build systems, primarily ninja. | 7 build systems, primarily ninja. |
| 8 """ | 8 """ |
| 9 | 9 |
| 10 import os | 10 import os |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 # normalized correctly. | 55 # normalized correctly. |
| 56 if not args: return '' | 56 if not args: return '' |
| 57 if args[0].startswith('call '): | 57 if args[0].startswith('call '): |
| 58 call, program = args[0].split(' ', 1) | 58 call, program = args[0].split(' ', 1) |
| 59 program = call + ' ' + os.path.normpath(program) | 59 program = call + ' ' + os.path.normpath(program) |
| 60 else: | 60 else: |
| 61 program = os.path.normpath(args[0]) | 61 program = os.path.normpath(args[0]) |
| 62 return program + ' ' + ' '.join(QuoteForRspFile(arg) for arg in args[1:]) | 62 return program + ' ' + ' '.join(QuoteForRspFile(arg) for arg in args[1:]) |
| 63 | 63 |
| 64 | 64 |
| 65 def _WriteIfChanged(open_output, filename, contents): | |
| 66 """Writes the specified contents to the specified filename if the contents | |
| 67 are different than the current contents.""" | |
| 68 try: | |
| 69 with open(filename, 'rb') as f: | |
| 70 old_contents = f.read() | |
| 71 except EnvironmentError: | |
| 72 pass | |
| 73 else: | |
| 74 if contents == old_contents: | |
| 75 return | |
| 76 with open_output(filename, 'wb') as f: | |
| 77 f.write(contents) | |
|
Nico
2013/12/12 17:45:54
(There's gyp.common.WriteOnDiff fwiw. It's a bit o
scottmg
2013/12/12 18:14:05
Thanks, done with a little rejiggering.
That func
| |
| 78 | |
| 79 | |
| 65 def _GenericRetrieve(root, default, path): | 80 def _GenericRetrieve(root, default, path): |
| 66 """Given a list of dictionary keys |path| and a tree of dicts |root|, find | 81 """Given a list of dictionary keys |path| and a tree of dicts |root|, find |
| 67 value at path, or return |default| if any of the path doesn't exist.""" | 82 value at path, or return |default| if any of the path doesn't exist.""" |
| 68 if not root: | 83 if not root: |
| 69 return default | 84 return default |
| 70 if not path: | 85 if not path: |
| 71 return root | 86 return root |
| 72 return _GenericRetrieve(root.get(path[0]), default, path[1:]) | 87 return _GenericRetrieve(root.get(path[0]), default, path[1:]) |
| 73 | 88 |
| 74 | 89 |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 447 if it's not overridden.""" | 462 if it's not overridden.""" |
| 448 config = self._TargetConfig(config) | 463 config = self._TargetConfig(config) |
| 449 output_file = self._Setting( | 464 output_file = self._Setting( |
| 450 ('VCLinkerTool', 'ProfileGuidedDatabase'), config) | 465 ('VCLinkerTool', 'ProfileGuidedDatabase'), config) |
| 451 if output_file: | 466 if output_file: |
| 452 output_file = expand_special(self.ConvertVSMacros( | 467 output_file = expand_special(self.ConvertVSMacros( |
| 453 output_file, config=config)) | 468 output_file, config=config)) |
| 454 return output_file | 469 return output_file |
| 455 | 470 |
| 456 def GetLdflags(self, config, gyp_to_build_path, expand_special, | 471 def GetLdflags(self, config, gyp_to_build_path, expand_special, |
| 457 manifest_base_name, is_executable): | 472 manifest_base_name, is_executable, build_dir, open_output): |
| 458 """Returns the flags that need to be added to link commands, and the | 473 """Returns the flags that need to be added to link commands, and the |
| 459 manifest files.""" | 474 manifest files.""" |
| 460 config = self._TargetConfig(config) | 475 config = self._TargetConfig(config) |
| 461 ldflags = [] | 476 ldflags = [] |
| 462 ld = self._GetWrapper(self, self.msvs_settings[config], | 477 ld = self._GetWrapper(self, self.msvs_settings[config], |
| 463 'VCLinkerTool', append=ldflags) | 478 'VCLinkerTool', append=ldflags) |
| 464 self._GetDefFileAsLdflags(ldflags, gyp_to_build_path) | 479 self._GetDefFileAsLdflags(ldflags, gyp_to_build_path) |
| 465 ld('GenerateDebugInformation', map={'true': '/DEBUG'}) | 480 ld('GenerateDebugInformation', map={'true': '/DEBUG'}) |
| 466 ld('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:') | 481 ld('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:') |
| 467 ldflags.extend(self._GetAdditionalLibraryDirectories( | 482 ldflags.extend(self._GetAdditionalLibraryDirectories( |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 524 ldflags.append('/DYNAMICBASE') | 539 ldflags.append('/DYNAMICBASE') |
| 525 | 540 |
| 526 # If the NXCOMPAT flag has not been specified, default to on. Despite the | 541 # If the NXCOMPAT flag has not been specified, default to on. Despite the |
| 527 # documentation that says this only defaults to on when the subsystem is | 542 # documentation that says this only defaults to on when the subsystem is |
| 528 # Vista or greater (which applies to the linker), the IDE defaults it on | 543 # Vista or greater (which applies to the linker), the IDE defaults it on |
| 529 # unless it's explicitly off. | 544 # unless it's explicitly off. |
| 530 if not filter(lambda x: 'NXCOMPAT' in x, ldflags): | 545 if not filter(lambda x: 'NXCOMPAT' in x, ldflags): |
| 531 ldflags.append('/NXCOMPAT') | 546 ldflags.append('/NXCOMPAT') |
| 532 | 547 |
| 533 have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags) | 548 have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags) |
| 534 manifest_flags, manifest_files = self._GetLdManifestFlags( | 549 manifest_flags, intermediate_manifest, manifest_files = \ |
| 535 config, manifest_base_name, gyp_to_build_path, | 550 self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path, |
| 536 is_executable and not have_def_file) | 551 is_executable and not have_def_file, build_dir, |
| 552 open_output) | |
| 537 ldflags.extend(manifest_flags) | 553 ldflags.extend(manifest_flags) |
| 538 return ldflags, manifest_files | 554 return ldflags, intermediate_manifest, manifest_files |
| 539 | 555 |
| 540 def _GetLdManifestFlags(self, config, name, gyp_to_build_path, | 556 def _GetLdManifestFlags(self, config, name, gyp_to_build_path, |
| 541 allow_isolation): | 557 allow_isolation, build_dir, open_output): |
| 542 """Returns the set of flags that need to be added to the link to generate | 558 """Returns a 3-tuple: |
| 543 a default manifest, as well as the list of all the manifest files to be | 559 - the set of flags that need to be added to the link to generate |
| 544 merged by the manifest tool.""" | 560 a default manifest |
| 561 - the intermediate manifest that the linker will generate that should be | |
| 562 used to assert it doesn't add anything to the merged one. | |
| 563 - the list of all the manifest files to be merged by the manifest tool and | |
| 564 included into the link.""" | |
| 545 generate_manifest = self._Setting(('VCLinkerTool', 'GenerateManifest'), | 565 generate_manifest = self._Setting(('VCLinkerTool', 'GenerateManifest'), |
| 546 config, | 566 config, |
| 547 default='true') | 567 default='true') |
| 548 if generate_manifest != 'true': | 568 if generate_manifest != 'true': |
| 549 # This means not only that the linker should not generate the intermediate | 569 # This means not only that the linker should not generate the intermediate |
| 550 # manifest but also that the manifest tool should do nothing even when | 570 # manifest but also that the manifest tool should do nothing even when |
| 551 # additional manifests are specified. | 571 # additional manifests are specified. |
| 552 return ['/MANIFEST:NO'], [] | 572 return ['/MANIFEST:NO'], [], [] |
| 553 | 573 |
| 554 output_name = name + '.intermediate.manifest' | 574 output_name = name + '.intermediate.manifest' |
| 555 flags = [ | 575 flags = [ |
| 556 '/MANIFEST', | 576 '/MANIFEST', |
| 557 '/ManifestFile:' + output_name, | 577 '/ManifestFile:' + output_name, |
| 558 ] | 578 ] |
| 559 | 579 |
| 580 # Instead of using the MANIFESTUAC flags, we generate a .manifest to | |
| 581 # include into the list of manifests. This allows us to avoid the need to | |
| 582 # do two passes during linking. The /MANIFEST flag and /ManifestFile are | |
| 583 # still used, and the intermediate manifest is used to assert that the | |
| 584 # final manifest we get from merging all the additional manifest files | |
| 585 # (plus the one we generate here) isn't modified by merging the | |
| 586 # intermediate into it. | |
| 587 | |
| 588 # Always NO, because we generate a manifest file that has what we want. | |
| 589 flags.append('/MANIFESTUAC:NO') | |
| 590 | |
| 560 config = self._TargetConfig(config) | 591 config = self._TargetConfig(config) |
| 561 enable_uac = self._Setting(('VCLinkerTool', 'EnableUAC'), config, | 592 enable_uac = self._Setting(('VCLinkerTool', 'EnableUAC'), config, |
| 562 default='true') | 593 default='true') |
| 594 manifest_files = [] | |
| 595 generated_manifest_outer = \ | |
| 596 "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" \ | |
| 597 "<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>%s" \ | |
| 598 "</assembly>" | |
| 563 if enable_uac == 'true': | 599 if enable_uac == 'true': |
| 564 execution_level = self._Setting(('VCLinkerTool', 'UACExecutionLevel'), | 600 execution_level = self._Setting(('VCLinkerTool', 'UACExecutionLevel'), |
| 565 config, default='0') | 601 config, default='0') |
| 566 execution_level_map = { | 602 execution_level_map = { |
| 567 '0': 'asInvoker', | 603 '0': 'asInvoker', |
| 568 '1': 'highestAvailable', | 604 '1': 'highestAvailable', |
| 569 '2': 'requireAdministrator' | 605 '2': 'requireAdministrator' |
| 570 } | 606 } |
| 571 | 607 |
| 572 ui_access = self._Setting(('VCLinkerTool', 'UACUIAccess'), config, | 608 ui_access = self._Setting(('VCLinkerTool', 'UACUIAccess'), config, |
| 573 default='false') | 609 default='false') |
| 574 flags.append('''/MANIFESTUAC:"level='%s' uiAccess='%s'"''' % | 610 |
| 575 (execution_level_map[execution_level], ui_access)) | 611 inner = ''' |
| 612 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> | |
| 613 <security> | |
| 614 <requestedPrivileges> | |
| 615 <requestedExecutionLevel level='%s' uiAccess='%s' /> | |
| 616 </requestedPrivileges> | |
| 617 </security> | |
| 618 </trustInfo>''' % (execution_level_map[execution_level], ui_access) | |
| 576 else: | 619 else: |
| 577 flags.append('/MANIFESTUAC:NO') | 620 inner = '' |
| 621 | |
| 622 generated_manifest_contents = generated_manifest_outer % inner | |
| 623 generated_name = name + '.generated.manifest' | |
| 624 # Need to join with the build_dir here as we're writing it during | |
| 625 # generation time, but we return the un-joined version because the build | |
| 626 # will occur in that directory. We only write the file if the contents | |
| 627 # have changed so that simply regenerating the project files doesn't | |
| 628 # cause a relink. | |
| 629 _WriteIfChanged(open_output, | |
| 630 os.path.join(build_dir, generated_name), | |
| 631 generated_manifest_contents) | |
| 632 manifest_files = [generated_name] | |
| 578 | 633 |
| 579 if allow_isolation: | 634 if allow_isolation: |
| 580 flags.append('/ALLOWISOLATION') | 635 flags.append('/ALLOWISOLATION') |
| 581 | 636 |
| 582 manifest_files = [output_name] | |
| 583 manifest_files += self._GetAdditionalManifestFiles(config, | 637 manifest_files += self._GetAdditionalManifestFiles(config, |
| 584 gyp_to_build_path) | 638 gyp_to_build_path) |
| 585 return flags, manifest_files | 639 return flags, output_name, manifest_files |
| 586 | 640 |
| 587 def _GetAdditionalManifestFiles(self, config, gyp_to_build_path): | 641 def _GetAdditionalManifestFiles(self, config, gyp_to_build_path): |
| 588 """Gets additional manifest files that are added to the default one | 642 """Gets additional manifest files that are added to the default one |
| 589 generated by the linker.""" | 643 generated by the linker.""" |
| 590 files = self._Setting(('VCManifestTool', 'AdditionalManifestFiles'), config, | 644 files = self._Setting(('VCManifestTool', 'AdditionalManifestFiles'), config, |
| 591 default=[]) | 645 default=[]) |
| 592 if isinstance(files, str): | 646 if isinstance(files, str): |
| 593 files = files.split(';') | 647 files = files.split(';') |
| 594 return [os.path.normpath( | 648 return [os.path.normpath( |
| 595 gyp_to_build_path(self.ConvertVSMacros(f, config=config))) | 649 gyp_to_build_path(self.ConvertVSMacros(f, config=config))) |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 903 | 957 |
| 904 # To determine processor word size on Windows, in addition to checking | 958 # To determine processor word size on Windows, in addition to checking |
| 905 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current | 959 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current |
| 906 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which | 960 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which |
| 907 # contains the actual word size of the system when running thru WOW64). | 961 # contains the actual word size of the system when running thru WOW64). |
| 908 if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or | 962 if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or |
| 909 '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')): | 963 '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')): |
| 910 default_variables['MSVS_OS_BITS'] = 64 | 964 default_variables['MSVS_OS_BITS'] = 64 |
| 911 else: | 965 else: |
| 912 default_variables['MSVS_OS_BITS'] = 32 | 966 default_variables['MSVS_OS_BITS'] = 32 |
| OLD | NEW |