Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: test/lib/TestGyp.py

Issue 245923003: Fix msvs-ninja OutputDirectory path. (Closed) Base URL: http://gyp.googlecode.com/svn/trunk/
Patch Set: Use reg.exe instead of _winreg. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « test/ios/gyptest-xcode-ninja.py ('k') | test/lib/TestWin.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 TestGyp.py: a testing framework for GYP integration tests. 6 TestGyp.py: a testing framework for GYP integration tests.
7 """ 7 """
8 8
9 import collections 9 import collections
10 from contextlib import contextmanager 10 from contextlib import contextmanager
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 The default behavior is to test the 'gyp' or 'gyp.bat' file in the 71 The default behavior is to test the 'gyp' or 'gyp.bat' file in the
72 current directory. An alternative may be specified explicitly on 72 current directory. An alternative may be specified explicitly on
73 instantiation, or by setting the TESTGYP_GYP environment variable. 73 instantiation, or by setting the TESTGYP_GYP environment variable.
74 74
75 This class should be subclassed for each supported gyp generator 75 This class should be subclassed for each supported gyp generator
76 (format). Various abstract methods below define calling signatures 76 (format). Various abstract methods below define calling signatures
77 used by the test scripts to invoke builds on the generated build 77 used by the test scripts to invoke builds on the generated build
78 configuration and to run executables generated by those builds. 78 configuration and to run executables generated by those builds.
79 """ 79 """
80 80
81 formats = []
81 build_tool = None 82 build_tool = None
82 build_tool_list = [] 83 build_tool_list = []
83 84
84 _exe = TestCommon.exe_suffix 85 _exe = TestCommon.exe_suffix
85 _obj = TestCommon.obj_suffix 86 _obj = TestCommon.obj_suffix
86 shobj_ = TestCommon.shobj_prefix 87 shobj_ = TestCommon.shobj_prefix
87 _shobj = TestCommon.shobj_suffix 88 _shobj = TestCommon.shobj_suffix
88 lib_ = TestCommon.lib_prefix 89 lib_ = TestCommon.lib_prefix
89 _lib = TestCommon.lib_suffix 90 _lib = TestCommon.lib_suffix
90 dll_ = TestCommon.dll_prefix 91 dll_ = TestCommon.dll_prefix
(...skipping 15 matching lines...) Expand all
106 if not gyp: 107 if not gyp:
107 gyp = os.environ.get('TESTGYP_GYP') 108 gyp = os.environ.get('TESTGYP_GYP')
108 if not gyp: 109 if not gyp:
109 if sys.platform == 'win32': 110 if sys.platform == 'win32':
110 gyp = 'gyp.bat' 111 gyp = 'gyp.bat'
111 else: 112 else:
112 gyp = 'gyp' 113 gyp = 'gyp'
113 self.gyp = os.path.abspath(gyp) 114 self.gyp = os.path.abspath(gyp)
114 self.no_parallel = False 115 self.no_parallel = False
115 116
117 self.formats = [self.format]
118
116 self.initialize_build_tool() 119 self.initialize_build_tool()
117 120
118 kw.setdefault('match', TestCommon.match_exact) 121 kw.setdefault('match', TestCommon.match_exact)
119 122
120 # Put test output in out/testworkarea by default. 123 # Put test output in out/testworkarea by default.
121 # Use temporary names so there are no collisions. 124 # Use temporary names so there are no collisions.
122 workdir = os.path.join('out', kw.get('workdir', 'testworkarea')) 125 workdir = os.path.join('out', kw.get('workdir', 'testworkarea'))
123 # Create work area if it doesn't already exist. 126 # Create work area if it doesn't already exist.
124 if not os.path.isdir(workdir): 127 if not os.path.isdir(workdir):
125 os.makedirs(workdir) 128 os.makedirs(workdir)
126 129
127 kw['workdir'] = tempfile.mktemp(prefix='testgyp.', dir=workdir) 130 kw['workdir'] = tempfile.mktemp(prefix='testgyp.', dir=workdir)
128 131
129 formats = kw.pop('formats', []) 132 formats = kw.pop('formats', [])
130 133
131 super(TestGypBase, self).__init__(*args, **kw) 134 super(TestGypBase, self).__init__(*args, **kw)
132 135
136 real_format = self.format.split('-')[-1]
133 excluded_formats = set([f for f in formats if f[0] == '!']) 137 excluded_formats = set([f for f in formats if f[0] == '!'])
134 included_formats = set(formats) - excluded_formats 138 included_formats = set(formats) - excluded_formats
135 if ('!'+self.format in excluded_formats or 139 if ('!'+real_format in excluded_formats or
136 included_formats and self.format not in included_formats): 140 included_formats and real_format not in included_formats):
137 msg = 'Invalid test for %r format; skipping test.\n' 141 msg = 'Invalid test for %r format; skipping test.\n'
138 self.skip_test(msg % self.format) 142 self.skip_test(msg % self.format)
139 143
140 self.copy_test_configuration(self.origin_cwd, self.workdir) 144 self.copy_test_configuration(self.origin_cwd, self.workdir)
141 self.set_configuration(None) 145 self.set_configuration(None)
142 146
143 # Set $HOME so that gyp doesn't read the user's actual 147 # Set $HOME so that gyp doesn't read the user's actual
144 # ~/.gyp/include.gypi file, which may contain variables 148 # ~/.gyp/include.gypi file, which may contain variables
145 # and other settings that would change the output. 149 # and other settings that would change the output.
146 os.environ['HOME'] = self.workpath() 150 os.environ['HOME'] = self.workpath()
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 Runs gyp against the specified gyp_file with the specified args. 269 Runs gyp against the specified gyp_file with the specified args.
266 """ 270 """
267 271
268 # When running gyp, and comparing its output we use a comparitor 272 # When running gyp, and comparing its output we use a comparitor
269 # that ignores the line numbers that gyp logs in its debug output. 273 # that ignores the line numbers that gyp logs in its debug output.
270 if kw.pop('ignore_line_numbers', False): 274 if kw.pop('ignore_line_numbers', False):
271 kw.setdefault('match', match_modulo_line_numbers) 275 kw.setdefault('match', match_modulo_line_numbers)
272 276
273 # TODO: --depth=. works around Chromium-specific tree climbing. 277 # TODO: --depth=. works around Chromium-specific tree climbing.
274 depth = kw.pop('depth', '.') 278 depth = kw.pop('depth', '.')
275 run_args = ['--depth='+depth, '--format='+self.format, gyp_file] 279 run_args = ['--depth='+depth]
280 run_args.extend(['--format='+f for f in self.formats]);
281 run_args.append(gyp_file)
276 if self.no_parallel: 282 if self.no_parallel:
277 run_args += ['--no-parallel'] 283 run_args += ['--no-parallel']
284 # TODO: if extra_args contains a '--build' flag
285 # we really want that to only apply to the last format (self.format).
278 run_args.extend(self.extra_args) 286 run_args.extend(self.extra_args)
279 run_args.extend(args) 287 run_args.extend(args)
280 return self.run(program=self.gyp, arguments=run_args, **kw) 288 return self.run(program=self.gyp, arguments=run_args, **kw)
281 289
282 def run(self, *args, **kw): 290 def run(self, *args, **kw):
283 """ 291 """
284 Executes a program by calling the superclass .run() method. 292 Executes a program by calling the superclass .run() method.
285 293
286 This exists to provide a common place to filter out keyword 294 This exists to provide a common place to filter out keyword
287 arguments implemented in this layer, without having to update 295 arguments implemented in this layer, without having to update
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after
740 748
741 749
742 def ConvertToCygpath(path): 750 def ConvertToCygpath(path):
743 """Convert to cygwin path if we are using cygwin.""" 751 """Convert to cygwin path if we are using cygwin."""
744 if sys.platform == 'cygwin': 752 if sys.platform == 'cygwin':
745 p = subprocess.Popen(['cygpath', path], stdout=subprocess.PIPE) 753 p = subprocess.Popen(['cygpath', path], stdout=subprocess.PIPE)
746 path = p.communicate()[0].strip() 754 path = p.communicate()[0].strip()
747 return path 755 return path
748 756
749 757
758 def FindMSBuildInstallation(msvs_version = 'auto'):
759 """Returns path to MSBuild for msvs_version or latest available.
760
761 Looks in the registry to find install location of MSBuild.
762 MSBuild before v4.0 will not build c++ projects, so only use newer versions.
763 """
764 import TestWin
765 registry = TestWin.Registry()
766
767 msvs_to_msbuild = {
768 '2013': r'12.0',
769 '2012': r'4.0', # Really v4.0.30319 which comes with .NET 4.5.
770 '2010': r'4.0'}
771
772 msbuild_basekey = r'HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions'
773 if not registry.KeyExists(msbuild_basekey):
774 print 'Error: could not find MSBuild base registry entry'
775 return None
776
777 msbuild_version = None
778 if msvs_version in msvs_to_msbuild:
779 msbuild_test_version = msvs_to_msbuild[msvs_version]
780 if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version):
781 msbuild_version = msbuild_test_version
782 else:
783 print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
784 'but corresponding MSBuild "%s" was not found.' %
785 (msvs_version, msbuild_version))
786 if not msbuild_version:
787 for msvs_version in sorted(msvs_to_msbuild, reverse=True):
788 msbuild_test_version = msvs_to_msbuild[msvs_version]
789 if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version):
790 msbuild_version = msbuild_test_version
791 break
792 if not msbuild_version:
793 print 'Error: could not find MSBuild registry entry'
794 return None
795
796 msbuild_path = registry.GetValue(msbuild_basekey + '\\' + msbuild_version,
797 'MSBuildToolsPath')
798 if not msbuild_path:
799 print 'Error: could not get MSBuild registry entry value'
800 return None
801
802 return os.path.join(msbuild_path, 'MSBuild.exe')
803
804
750 def FindVisualStudioInstallation(): 805 def FindVisualStudioInstallation():
751 """Returns appropriate values for .build_tool and .uses_msbuild fields 806 """Returns appropriate values for .build_tool and .uses_msbuild fields
752 of TestGypBase for Visual Studio. 807 of TestGypBase for Visual Studio.
753 808
754 We use the value specified by GYP_MSVS_VERSION. If not specified, we 809 We use the value specified by GYP_MSVS_VERSION. If not specified, we
755 search %PATH% and %PATHEXT% for a devenv.{exe,bat,...} executable. 810 search %PATH% and %PATHEXT% for a devenv.{exe,bat,...} executable.
756 Failing that, we search for likely deployment paths. 811 Failing that, we search for likely deployment paths.
757 """ 812 """
758 possible_roots = ['%s:\\Program Files%s' % (chr(drive), suffix) 813 possible_roots = ['%s:\\Program Files%s' % (chr(drive), suffix)
759 for drive in range(ord('C'), ord('Z') + 1) 814 for drive in range(ord('C'), ord('Z') + 1)
760 for suffix in ['', ' (x86)']] 815 for suffix in ['', ' (x86)']]
761 possible_paths = { 816 possible_paths = {
762 '2013': r'Microsoft Visual Studio 12.0\Common7\IDE\devenv.com', 817 '2013': r'Microsoft Visual Studio 12.0\Common7\IDE\devenv.com',
763 '2012': r'Microsoft Visual Studio 11.0\Common7\IDE\devenv.com', 818 '2012': r'Microsoft Visual Studio 11.0\Common7\IDE\devenv.com',
764 '2010': r'Microsoft Visual Studio 10.0\Common7\IDE\devenv.com', 819 '2010': r'Microsoft Visual Studio 10.0\Common7\IDE\devenv.com',
765 '2008': r'Microsoft Visual Studio 9.0\Common7\IDE\devenv.com', 820 '2008': r'Microsoft Visual Studio 9.0\Common7\IDE\devenv.com',
766 '2005': r'Microsoft Visual Studio 8\Common7\IDE\devenv.com'} 821 '2005': r'Microsoft Visual Studio 8\Common7\IDE\devenv.com'}
767 822
768 possible_roots = [ConvertToCygpath(r) for r in possible_roots] 823 possible_roots = [ConvertToCygpath(r) for r in possible_roots]
769 824
770 msvs_version = 'auto' 825 msvs_version = 'auto'
771 for flag in (f for f in sys.argv if f.startswith('msvs_version=')): 826 for flag in (f for f in sys.argv if f.startswith('msvs_version=')):
772 msvs_version = flag.split('=')[-1] 827 msvs_version = flag.split('=')[-1]
773 msvs_version = os.environ.get('GYP_MSVS_VERSION', msvs_version) 828 msvs_version = os.environ.get('GYP_MSVS_VERSION', msvs_version)
774 829
775 build_tool = None
776 if msvs_version in possible_paths: 830 if msvs_version in possible_paths:
777 # Check that the path to the specified GYP_MSVS_VERSION exists. 831 # Check that the path to the specified GYP_MSVS_VERSION exists.
778 path = possible_paths[msvs_version] 832 path = possible_paths[msvs_version]
779 for r in possible_roots: 833 for r in possible_roots:
780 bt = os.path.join(r, path) 834 build_tool = os.path.join(r, path)
781 if os.path.exists(bt): 835 if os.path.exists(build_tool):
782 build_tool = bt
783 uses_msbuild = msvs_version >= '2010' 836 uses_msbuild = msvs_version >= '2010'
784 return build_tool, uses_msbuild 837 msbuild_path = FindMSBuildInstallation(msvs_version)
838 return build_tool, uses_msbuild, msbuild_path
785 else: 839 else:
786 print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" ' 840 print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
787 'but corresponding "%s" was not found.' % (msvs_version, path)) 841 'but corresponding "%s" was not found.' % (msvs_version, path))
788 if build_tool:
789 # We found 'devenv' on the path, use that and try to guess the version.
790 for version, path in possible_paths.iteritems():
791 if build_tool.find(path) >= 0:
792 uses_msbuild = version >= '2010'
793 return build_tool, uses_msbuild
794 else:
795 # If not, assume not MSBuild.
796 uses_msbuild = False
797 return build_tool, uses_msbuild
798 # Neither GYP_MSVS_VERSION nor the path help us out. Iterate through 842 # Neither GYP_MSVS_VERSION nor the path help us out. Iterate through
799 # the choices looking for a match. 843 # the choices looking for a match.
800 for version in sorted(possible_paths, reverse=True): 844 for version in sorted(possible_paths, reverse=True):
801 path = possible_paths[version] 845 path = possible_paths[version]
802 for r in possible_roots: 846 for r in possible_roots:
803 bt = os.path.join(r, path) 847 build_tool = os.path.join(r, path)
804 if os.path.exists(bt): 848 if os.path.exists(build_tool):
805 build_tool = bt
806 uses_msbuild = msvs_version >= '2010' 849 uses_msbuild = msvs_version >= '2010'
807 return build_tool, uses_msbuild 850 msbuild_path = FindMSBuildInstallation(msvs_version)
851 return build_tool, uses_msbuild, msbuild_path
808 print 'Error: could not find devenv' 852 print 'Error: could not find devenv'
809 sys.exit(1) 853 sys.exit(1)
810 854
811 class TestGypOnMSToolchain(TestGypBase): 855 class TestGypOnMSToolchain(TestGypBase):
812 """ 856 """
813 Common subclass for testing generators that target the Microsoft Visual 857 Common subclass for testing generators that target the Microsoft Visual
814 Studio toolchain (cl, link, dumpbin, etc.) 858 Studio toolchain (cl, link, dumpbin, etc.)
815 """ 859 """
816 @staticmethod 860 @staticmethod
817 def _ComputeVsvarsPath(devenv_path): 861 def _ComputeVsvarsPath(devenv_path):
818 devenv_dir = os.path.split(devenv_path)[0] 862 devenv_dir = os.path.split(devenv_path)[0]
819 vsvars_path = os.path.join(devenv_path, '../../Tools/vsvars32.bat') 863 vsvars_path = os.path.join(devenv_path, '../../Tools/vsvars32.bat')
820 return vsvars_path 864 return vsvars_path
821 865
822 def initialize_build_tool(self): 866 def initialize_build_tool(self):
823 super(TestGypOnMSToolchain, self).initialize_build_tool() 867 super(TestGypOnMSToolchain, self).initialize_build_tool()
824 if sys.platform in ('win32', 'cygwin'): 868 if sys.platform in ('win32', 'cygwin'):
825 self.devenv_path, self.uses_msbuild = FindVisualStudioInstallation() 869 build_tools = FindVisualStudioInstallation()
870 self.devenv_path, self.uses_msbuild, self.msbuild_path = build_tools
826 self.vsvars_path = TestGypOnMSToolchain._ComputeVsvarsPath( 871 self.vsvars_path = TestGypOnMSToolchain._ComputeVsvarsPath(
827 self.devenv_path) 872 self.devenv_path)
828 873
829 def run_dumpbin(self, *dumpbin_args): 874 def run_dumpbin(self, *dumpbin_args):
830 """Run the dumpbin tool with the specified arguments, and capturing and 875 """Run the dumpbin tool with the specified arguments, and capturing and
831 returning stdout.""" 876 returning stdout."""
832 assert sys.platform in ('win32', 'cygwin') 877 assert sys.platform in ('win32', 'cygwin')
833 cmd = os.environ.get('COMSPEC', 'cmd.exe') 878 cmd = os.environ.get('COMSPEC', 'cmd.exe')
834 arguments = [cmd, '/c', self.vsvars_path, '&&', 'dumpbin'] 879 arguments = [cmd, '/c', self.vsvars_path, '&&', 'dumpbin']
835 arguments.extend(dumpbin_args) 880 arguments.extend(dumpbin_args)
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
995 chdir = kw.get('chdir') 1040 chdir = kw.get('chdir')
996 if chdir: 1041 if chdir:
997 result.append(chdir) 1042 result.append(chdir)
998 result.append(self.configuration_dirname()) 1043 result.append(self.configuration_dirname())
999 if type == self.STATIC_LIB: 1044 if type == self.STATIC_LIB:
1000 result.append('lib') 1045 result.append('lib')
1001 result.append(self.built_file_basename(name, type, **kw)) 1046 result.append(self.built_file_basename(name, type, **kw))
1002 return self.workpath(*result) 1047 return self.workpath(*result)
1003 1048
1004 1049
1050 class TestGypMSVSNinja(TestGypNinja):
1051 """
1052 Subclass for testing the GYP Visual Studio Ninja generator.
1053 """
1054 format = 'msvs-ninja'
1055
1056 def initialize_build_tool(self):
1057 super(TestGypMSVSNinja, self).initialize_build_tool()
1058 # When using '--build', make sure ninja is first in the format list.
1059 self.formats.insert(0, 'ninja')
1060
1061 def build(self, gyp_file, target=None, rebuild=False, clean=False, **kw):
1062 """
1063 Runs a Visual Studio build using the configuration generated
1064 from the specified gyp_file.
1065 """
1066 arguments = kw.get('arguments', [])[:]
1067 if target in (None, self.ALL, self.DEFAULT):
1068 # Note: the Visual Studio generator doesn't add an explicit 'all' target.
1069 # This will build each project. This will work if projects are hermetic,
1070 # but may fail if they are not (a project may run more than once).
1071 # It would be nice to supply an all.metaproj for MSBuild.
1072 arguments.extend([gyp_file.replace('.gyp', '.sln')])
1073 else:
1074 # MSBuild documentation claims that one can specify a sln but then build a
1075 # project target like 'msbuild a.sln /t:proj:target' but this format only
1076 # supports 'Clean', 'Rebuild', and 'Publish' (with none meaning Default).
1077 # This limitation is due to the .sln -> .sln.metaproj conversion.
1078 # The ':' is not special, 'proj:target' is a target in the metaproj.
1079 arguments.extend([target+'.vcxproj'])
1080
1081 if clean:
1082 build = 'Clean'
1083 elif rebuild:
1084 build = 'Rebuild'
1085 else:
1086 build = 'Build'
1087 arguments.extend(['/target:'+build])
1088 configuration = self.configuration_buildname()
1089 config = configuration.split('|')
1090 arguments.extend(['/property:Configuration='+config[0]])
1091 if len(config) > 1:
1092 arguments.extend(['/property:Platform='+config[1]])
1093 arguments.extend(['/property:BuildInParallel=false'])
1094 arguments.extend(['/verbosity:minimal'])
1095
1096 kw['arguments'] = arguments
1097 return self.run(program=self.msbuild_path, **kw)
1098
1099
1005 class TestGypXcode(TestGypBase): 1100 class TestGypXcode(TestGypBase):
1006 """ 1101 """
1007 Subclass for testing the GYP Xcode generator. 1102 Subclass for testing the GYP Xcode generator.
1008 """ 1103 """
1009 format = 'xcode' 1104 format = 'xcode'
1010 build_tool_list = ['xcodebuild'] 1105 build_tool_list = ['xcodebuild']
1011 1106
1012 phase_script_execution = ("\n" 1107 phase_script_execution = ("\n"
1013 "PhaseScriptExecution /\\S+/Script-[0-9A-F]+\\.sh\n" 1108 "PhaseScriptExecution /\\S+/Script-[0-9A-F]+\\.sh\n"
1014 " cd /\\S+\n" 1109 " cd /\\S+\n"
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
1111 result.append(self.built_file_basename(name, type, **kw)) 1206 result.append(self.built_file_basename(name, type, **kw))
1112 return self.workpath(*result) 1207 return self.workpath(*result)
1113 1208
1114 1209
1115 format_class_list = [ 1210 format_class_list = [
1116 TestGypGypd, 1211 TestGypGypd,
1117 TestGypAndroid, 1212 TestGypAndroid,
1118 TestGypCMake, 1213 TestGypCMake,
1119 TestGypMake, 1214 TestGypMake,
1120 TestGypMSVS, 1215 TestGypMSVS,
1216 TestGypMSVSNinja,
1121 TestGypNinja, 1217 TestGypNinja,
1122 TestGypXcode, 1218 TestGypXcode,
1123 ] 1219 ]
1124 1220
1125 def TestGyp(*args, **kw): 1221 def TestGyp(*args, **kw):
1126 """ 1222 """
1127 Returns an appropriate TestGyp* instance for a specified GYP format. 1223 Returns an appropriate TestGyp* instance for a specified GYP format.
1128 """ 1224 """
1129 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT')) 1225 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT'))
1130 for format_class in format_class_list: 1226 for format_class in format_class_list:
1131 if format == format_class.format: 1227 if format == format_class.format:
1132 return format_class(*args, **kw) 1228 return format_class(*args, **kw)
1133 raise Exception, "unknown format %r" % format 1229 raise Exception, "unknown format %r" % format
OLDNEW
« no previous file with comments | « test/ios/gyptest-xcode-ninja.py ('k') | test/lib/TestWin.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698