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

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: Find MSBuild with registry. 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') | no next file » | 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 490 matching lines...) Expand 10 before | Expand all | Expand 10 after
778 path = possible_paths[msvs_version] 786 path = possible_paths[msvs_version]
779 for r in possible_roots: 787 for r in possible_roots:
780 bt = os.path.join(r, path) 788 bt = os.path.join(r, path)
781 if os.path.exists(bt): 789 if os.path.exists(bt):
782 build_tool = bt 790 build_tool = bt
783 uses_msbuild = msvs_version >= '2010' 791 uses_msbuild = msvs_version >= '2010'
784 return build_tool, uses_msbuild 792 return build_tool, uses_msbuild
785 else: 793 else:
786 print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" ' 794 print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
787 'but corresponding "%s" was not found.' % (msvs_version, path)) 795 'but corresponding "%s" was not found.' % (msvs_version, path))
788 if build_tool: 796 if build_tool:
bungeman-chromium 2014/05/30 22:18:09 This code never runs, so removing it.
789 # We found 'devenv' on the path, use that and try to guess the version. 797 # We found 'devenv' on the path, use that and try to guess the version.
790 for version, path in possible_paths.iteritems(): 798 for version, path in possible_paths.iteritems():
791 if build_tool.find(path) >= 0: 799 if build_tool.find(path) >= 0:
792 uses_msbuild = version >= '2010' 800 uses_msbuild = version >= '2010'
793 return build_tool, uses_msbuild 801 return build_tool, uses_msbuild
794 else: 802 else:
795 # If not, assume not MSBuild. 803 # If not, assume not MSBuild.
796 uses_msbuild = False 804 uses_msbuild = False
797 return build_tool, uses_msbuild 805 return build_tool, uses_msbuild
798 # Neither GYP_MSVS_VERSION nor the path help us out. Iterate through 806 # Neither GYP_MSVS_VERSION nor the path help us out. Iterate through
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
995 chdir = kw.get('chdir') 1003 chdir = kw.get('chdir')
996 if chdir: 1004 if chdir:
997 result.append(chdir) 1005 result.append(chdir)
998 result.append(self.configuration_dirname()) 1006 result.append(self.configuration_dirname())
999 if type == self.STATIC_LIB: 1007 if type == self.STATIC_LIB:
1000 result.append('lib') 1008 result.append('lib')
1001 result.append(self.built_file_basename(name, type, **kw)) 1009 result.append(self.built_file_basename(name, type, **kw))
1002 return self.workpath(*result) 1010 return self.workpath(*result)
1003 1011
1004 1012
1013 def FindMSBuildInstallation():
bungeman-chromium 2014/05/30 22:18:09 This is the better way to find MSBuild, not integr
1014 """Returns path to MSBuild for GYP_MSVS_VERSION, msvs_version,
1015 or latest available.
1016
1017 Looks in the registry to find install location of MSBuild.
1018 MSBuild before v4.0 will not build c++ projects, so only use newer versions.
1019 """
1020 import _winreg
1021 def get_reg_key(base, key):
1022 try:
1023 result = _winreg.OpenKey(base, key, 0,
1024 _winreg.KEY_READ | _winreg.KEY_WOW64_32KEY)
1025 except WindowsError:
1026 result = None
1027 return result
1028
1029 def get_reg_key_value(key, value):
1030 try:
1031 result, _ = _winreg.QueryValueEx(key, value)
1032 except WindowsError:
1033 result = None
1034 return result
1035
1036 msbuild_basekey = get_reg_key(_winreg.HKEY_LOCAL_MACHINE,
1037 'SOFTWARE\Microsoft\MSBuild\ToolsVersions')
1038 if not msbuild_basekey:
1039 print 'Error: could not find MSBuild base registry entry'
1040 sys.exit(1)
1041
1042 msvs_to_msbuild = {
1043 '2013': r'12.0',
1044 '2012': r'4.0', #really v4.0.30319 which comes with .NET 4.5
1045 '2010': r'4.0'}
1046
1047 msvs_version = 'auto'
1048 for flag in (f for f in sys.argv if f.startswith('msvs_version=')):
1049 msvs_version = flag.split('=')[-1]
1050 msvs_version = os.environ.get('GYP_MSVS_VERSION', msvs_version)
1051
1052 msbuild_key = None
1053 if msvs_version in msvs_to_msbuild:
1054 msbuild_version = msvs_to_msbuild[msvs_version]
1055 msbuild_key = get_reg_key(msbuild_basekey, msbuild_version)
1056 if not msbuild_key:
1057 print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
1058 'but corresponding MSBuild "%s" was not found.' %
1059 (msvs_version, msbuild_version))
1060 if not msbuild_key:
1061 for msvs_version in sorted(msvs_to_msbuild, reverse=True):
1062 msbuild_version = msvs_to_msbuild[msvs_version]
1063 msbuild_key = get_reg_key(msbuild_basekey, msbuild_version)
1064 if not msbuild_key:
1065 print 'Error: could not find MSBuild registry entry'
1066 sys.exit(1)
1067
1068 msbuild_path = get_reg_key_value(msbuild_key, 'MSBuildToolsPath')
1069 if not msbuild_path:
1070 print 'Error: could not get MSBuild registry entry value'
1071 sys.exit(1)
1072
1073 return os.path.join(msbuild_path, 'MSBuild.exe')
1074
1075
1076 class TestGypMSVSNinja(TestGypNinja):
1077 """
1078 Subclass for testing the GYP Visual Studio Ninja generator.
1079 """
1080 format = 'msvs-ninja'
1081
1082 def initialize_build_tool(self):
1083 super(TestGypMSVSNinja, self).initialize_build_tool()
1084 self.msbuild_path = FindMSBuildInstallation()
1085 # When using '--build', make sure ninja is first in the format list.
1086 self.formats.insert(0, 'ninja')
1087
1088 def build(self, gyp_file, target=None, rebuild=False, clean=False, **kw):
1089 """
1090 Runs a Visual Studio build using the configuration generated
1091 from the specified gyp_file.
1092 """
1093 arguments = kw.get('arguments', [])[:]
1094 if target in (None, self.ALL, self.DEFAULT):
1095 # Note: the Visual Studio generator doesn't add an explicit 'all' target.
1096 # This will build each project. This will work if projects are hermetic,
1097 # but may fail if they are not (a project may run more than once).
1098 # It would be nice to supply an all.metaproj for MSBuild.
1099 arguments.extend([gyp_file.replace('.gyp', '.sln')])
1100 else:
1101 # MSBuild documentation claims that one can specify a sln but then build a
1102 # project target like 'msbuild a.sln /t:proj:target' but this format only
1103 # supports 'Clean', 'Rebuild', and 'Publish' (with none meaning Default).
1104 # This limitation is due to the .sln -> .sln.metaproj conversion.
1105 # The ':' is not special, 'proj:target' is a target in the metaproj.
1106 arguments.extend([target+'.vcxproj'])
1107
1108 if clean:
1109 build = 'Clean'
1110 elif rebuild:
1111 build = 'Rebuild'
1112 else:
1113 build = 'Build'
1114 arguments.extend(['/target:'+build])
1115 configuration = self.configuration_buildname()
1116 config = configuration.split('|')
1117 arguments.extend(['/property:Configuration='+config[0]])
1118 if len(config) > 1:
1119 arguments.extend(['/property:Platform='+config[1]])
1120 arguments.extend(['/property:BuildInParallel=false'])
1121 arguments.extend(['/verbosity:minimal'])
1122
1123 kw['arguments'] = arguments
1124 return self.run(program=self.msbuild_path, **kw)
1125
1126
1005 class TestGypXcode(TestGypBase): 1127 class TestGypXcode(TestGypBase):
1006 """ 1128 """
1007 Subclass for testing the GYP Xcode generator. 1129 Subclass for testing the GYP Xcode generator.
1008 """ 1130 """
1009 format = 'xcode' 1131 format = 'xcode'
1010 build_tool_list = ['xcodebuild'] 1132 build_tool_list = ['xcodebuild']
1011 1133
1012 phase_script_execution = ("\n" 1134 phase_script_execution = ("\n"
1013 "PhaseScriptExecution /\\S+/Script-[0-9A-F]+\\.sh\n" 1135 "PhaseScriptExecution /\\S+/Script-[0-9A-F]+\\.sh\n"
1014 " cd /\\S+\n" 1136 " 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)) 1233 result.append(self.built_file_basename(name, type, **kw))
1112 return self.workpath(*result) 1234 return self.workpath(*result)
1113 1235
1114 1236
1115 format_class_list = [ 1237 format_class_list = [
1116 TestGypGypd, 1238 TestGypGypd,
1117 TestGypAndroid, 1239 TestGypAndroid,
1118 TestGypCMake, 1240 TestGypCMake,
1119 TestGypMake, 1241 TestGypMake,
1120 TestGypMSVS, 1242 TestGypMSVS,
1243 TestGypMSVSNinja,
1121 TestGypNinja, 1244 TestGypNinja,
1122 TestGypXcode, 1245 TestGypXcode,
1123 ] 1246 ]
1124 1247
1125 def TestGyp(*args, **kw): 1248 def TestGyp(*args, **kw):
1126 """ 1249 """
1127 Returns an appropriate TestGyp* instance for a specified GYP format. 1250 Returns an appropriate TestGyp* instance for a specified GYP format.
1128 """ 1251 """
1129 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT')) 1252 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT'))
1130 for format_class in format_class_list: 1253 for format_class in format_class_list:
1131 if format == format_class.format: 1254 if format == format_class.format:
1132 return format_class(*args, **kw) 1255 return format_class(*args, **kw)
1133 raise Exception, "unknown format %r" % format 1256 raise Exception, "unknown format %r" % format
OLDNEW
« no previous file with comments | « test/ios/gyptest-xcode-ninja.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698