16d528ed9Sopenharmony_ci# Copyright 2018 The Chromium Authors. All rights reserved. 26d528ed9Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be 36d528ed9Sopenharmony_ci# found in the LICENSE file. 46d528ed9Sopenharmony_ci 56d528ed9Sopenharmony_cifrom contextlib import contextmanager 66d528ed9Sopenharmony_ci 76d528ed9Sopenharmony_cifrom recipe_engine import recipe_api 86d528ed9Sopenharmony_ci 96d528ed9Sopenharmony_ci 106d528ed9Sopenharmony_ciclass WindowsSDKApi(recipe_api.RecipeApi): 116d528ed9Sopenharmony_ci """API for using Windows SDK distributed via CIPD.""" 126d528ed9Sopenharmony_ci 136d528ed9Sopenharmony_ci def __init__(self, sdk_properties, *args, **kwargs): 146d528ed9Sopenharmony_ci super(WindowsSDKApi, self).__init__(*args, **kwargs) 156d528ed9Sopenharmony_ci 166d528ed9Sopenharmony_ci self._sdk_package = sdk_properties['sdk_package'] 176d528ed9Sopenharmony_ci self._sdk_version = sdk_properties['sdk_version'] 186d528ed9Sopenharmony_ci 196d528ed9Sopenharmony_ci @contextmanager 206d528ed9Sopenharmony_ci def __call__(self): 216d528ed9Sopenharmony_ci """Setups the Windows SDK environment. 226d528ed9Sopenharmony_ci 236d528ed9Sopenharmony_ci This call is a no-op on non-Windows platforms. 246d528ed9Sopenharmony_ci 256d528ed9Sopenharmony_ci Raises: 266d528ed9Sopenharmony_ci StepFailure or InfraFailure. 276d528ed9Sopenharmony_ci """ 286d528ed9Sopenharmony_ci if not self.m.platform.is_win: 296d528ed9Sopenharmony_ci yield 306d528ed9Sopenharmony_ci return 316d528ed9Sopenharmony_ci 326d528ed9Sopenharmony_ci with self.m.context(infra_steps=True): 336d528ed9Sopenharmony_ci sdk_dir = self._ensure_sdk() 346d528ed9Sopenharmony_ci 356d528ed9Sopenharmony_ci with self.m.context(**self._sdk_env(sdk_dir)): 366d528ed9Sopenharmony_ci try: 376d528ed9Sopenharmony_ci yield 386d528ed9Sopenharmony_ci finally: 396d528ed9Sopenharmony_ci # cl.exe automatically starts background mspdbsrv.exe daemon which 406d528ed9Sopenharmony_ci # needs to be manually stopped so Swarming can tidy up after itself. 416d528ed9Sopenharmony_ci self.m.step('taskkill mspdbsrv', 426d528ed9Sopenharmony_ci ['taskkill.exe', '/f', '/t', '/im', 'mspdbsrv.exe']) 436d528ed9Sopenharmony_ci 446d528ed9Sopenharmony_ci def _ensure_sdk(self): 456d528ed9Sopenharmony_ci """Ensures the Windows SDK CIPD package is installed. 466d528ed9Sopenharmony_ci 476d528ed9Sopenharmony_ci Returns the directory where the SDK package has been installed. 486d528ed9Sopenharmony_ci 496d528ed9Sopenharmony_ci Args: 506d528ed9Sopenharmony_ci path (path): Path to a directory. 516d528ed9Sopenharmony_ci version (str): CIPD instance ID, tag or ref. 526d528ed9Sopenharmony_ci """ 536d528ed9Sopenharmony_ci sdk_dir = self.m.path['cache'].join('windows_sdk') 546d528ed9Sopenharmony_ci pkgs = self.m.cipd.EnsureFile() 556d528ed9Sopenharmony_ci pkgs.add_package(self._sdk_package, self._sdk_version) 566d528ed9Sopenharmony_ci self.m.cipd.ensure(sdk_dir, pkgs) 576d528ed9Sopenharmony_ci return sdk_dir 586d528ed9Sopenharmony_ci 596d528ed9Sopenharmony_ci def _sdk_env(self, sdk_dir): 606d528ed9Sopenharmony_ci """Constructs the environment for the SDK. 616d528ed9Sopenharmony_ci 626d528ed9Sopenharmony_ci Returns environment and environment prefixes. 636d528ed9Sopenharmony_ci 646d528ed9Sopenharmony_ci Args: 656d528ed9Sopenharmony_ci sdk_dir (path): Path to a directory containing the SDK. 666d528ed9Sopenharmony_ci """ 676d528ed9Sopenharmony_ci env = {} 686d528ed9Sopenharmony_ci env_prefixes = {} 696d528ed9Sopenharmony_ci 706d528ed9Sopenharmony_ci # Load .../Windows Kits/10/bin/SetEnv.${arch}.json to extract the required 716d528ed9Sopenharmony_ci # environment. It contains a dict that looks like this: 726d528ed9Sopenharmony_ci # { 736d528ed9Sopenharmony_ci # "env": { 746d528ed9Sopenharmony_ci # "VAR": [["x"], ["y"]], 756d528ed9Sopenharmony_ci # ... 766d528ed9Sopenharmony_ci # } 776d528ed9Sopenharmony_ci # } 786d528ed9Sopenharmony_ci # All these environment variables need to be added to the environment 796d528ed9Sopenharmony_ci # for the compiler and linker to work. 806d528ed9Sopenharmony_ci filename = 'SetEnv.%s.json' % {32: 'x86', 64: 'x64'}[self.m.platform.bits] 816d528ed9Sopenharmony_ci step_result = self.m.json.read( 826d528ed9Sopenharmony_ci 'read %s' % filename, 836d528ed9Sopenharmony_ci sdk_dir.join('Windows Kits', '10', 'bin', filename), 846d528ed9Sopenharmony_ci step_test_data=lambda: self.m.json.test_api.output({ 856d528ed9Sopenharmony_ci 'env': { 866d528ed9Sopenharmony_ci 'PATH': [['Windows Kits', '10', 'bin', '10.0.19041.0', 'x64']], 876d528ed9Sopenharmony_ci 'VSINSTALLDIR': [['.\\']], 886d528ed9Sopenharmony_ci }, 896d528ed9Sopenharmony_ci })) 906d528ed9Sopenharmony_ci data = step_result.json.output.get('env') 916d528ed9Sopenharmony_ci for key in data: 926d528ed9Sopenharmony_ci results = ['%s' % sdk_dir.join(*e) for e in data[key]] 936d528ed9Sopenharmony_ci 946d528ed9Sopenharmony_ci # PATH is special-cased because we don't want to overwrite other things 956d528ed9Sopenharmony_ci # like C:\Windows\System32. Others are replacements because prepending 966d528ed9Sopenharmony_ci # doesn't necessarily makes sense, like VSINSTALLDIR. 976d528ed9Sopenharmony_ci if key.lower() == 'path': 986d528ed9Sopenharmony_ci env_prefixes[key] = results 996d528ed9Sopenharmony_ci else: 1006d528ed9Sopenharmony_ci env[key] = ';'.join(results) 1016d528ed9Sopenharmony_ci 1026d528ed9Sopenharmony_ci return {'env': env, 'env_prefixes': env_prefixes} 103