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 |