From 2efe3d74baaa3f7918fe7a9fd0c00c7a6cc8a967 Mon Sep 17 00:00:00 2001 From: Robert Iannucci Date: Tue, 16 Nov 2021 21:15:35 +0000 Subject: [PATCH] [windows_sdk] Make sdk json-finding more flexible. R=ajgo@google.com Bug: 1250098 Recipe-Nontrivial-Roll: build Recipe-Nontrivial-Roll: build_limited Recipe-Nontrivial-Roll: infra Change-Id: I0a65193ed3c880ecfabef222ca85ea77bc3a75da Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/3283800 Auto-Submit: Robbie Iannucci Commit-Queue: Josip Sokcevic Reviewed-by: Josip Sokcevic Reviewed-by: Alex Gough --- recipes/README.recipes.md | 15 ++-- recipes/recipe_modules/windows_sdk/api.py | 45 ++++++------ .../examples/full.expected/linux.json | 39 +++++++++++ .../examples/full.expected/mac.json | 39 +++++++++++ .../examples/full.expected/win.json | 51 ++++++++++++-- .../windows_sdk/examples/full.py | 7 ++ .../windows_sdk/resources/find_env_json.py | 70 +++++++++++++++++++ 7 files changed, 233 insertions(+), 33 deletions(-) create mode 100755 recipes/recipe_modules/windows_sdk/resources/find_env_json.py diff --git a/recipes/README.recipes.md b/recipes/README.recipes.md index 0ae0f00f1..bdc84101b 100644 --- a/recipes/README.recipes.md +++ b/recipes/README.recipes.md @@ -14,7 +14,7 @@ * [osx_sdk](#recipe_modules-osx_sdk) (Python3 ✅) — The `osx_sdk` module provides safe functions to access a semi-hermetic XCode installation. * [presubmit](#recipe_modules-presubmit) (Python3 ✅) * [tryserver](#recipe_modules-tryserver) (Python3 ✅) - * [windows_sdk](#recipe_modules-windows_sdk) (Python3 ✅) — The `windows_sdk` module provides safe functions to access a hermetic Microsoft Visual Studio installation. + * [windows_sdk](#recipe_modules-windows_sdk) (Python3 ✅) — The `windows_sdk` module provides safe functions to access a hermetic Microsoft Visual Studio installation which is derived from Chromium's MSVC toolchain. **[Recipes](#Recipes)** * [bot_update:examples/full](#recipes-bot_update_examples_full) (Python3 ✅) @@ -920,15 +920,20 @@ timeout. PYTHON_VERSION_COMPATIBILITY: PY2+3 The `windows_sdk` module provides safe functions to access a hermetic -Microsoft Visual Studio installation. +Microsoft Visual Studio installation which is derived from Chromium's MSVC +toolchain. -Available only to Google-run bots. +See (internal): + * go/chromium-msvc-toolchain + * go/windows-sdk-cipd-update + +Available only on Google-run bots. -#### **class [WindowsSDKApi](/recipes/recipe_modules/windows_sdk/api.py#17)([RecipeApi][recipe_engine/wkt/RecipeApi]):** +#### **class [WindowsSDKApi](/recipes/recipe_modules/windows_sdk/api.py#22)([RecipeApi][recipe_engine/wkt/RecipeApi]):** API for using Windows SDK distributed via CIPD. -  **@contextmanager**
— **def [\_\_call\_\_](/recipes/recipe_modules/windows_sdk/api.py#27)(self, path=None, version=None, enabled=True, target_arch='x64'):** +  **@contextmanager**
— **def [\_\_call\_\_](/recipes/recipe_modules/windows_sdk/api.py#32)(self, path=None, version=None, enabled=True, target_arch='x64'):** Sets up the SDK environment when enabled. diff --git a/recipes/recipe_modules/windows_sdk/api.py b/recipes/recipe_modules/windows_sdk/api.py index 2d0e1aab2..6249c9a7c 100644 --- a/recipes/recipe_modules/windows_sdk/api.py +++ b/recipes/recipe_modules/windows_sdk/api.py @@ -3,9 +3,14 @@ # found in the LICENSE file. """The `windows_sdk` module provides safe functions to access a hermetic -Microsoft Visual Studio installation. +Microsoft Visual Studio installation which is derived from Chromium's MSVC +toolchain. -Available only to Google-run bots. +See (internal): + * go/chromium-msvc-toolchain + * go/windows-sdk-cipd-update + +Available only on Google-run bots. """ import collections @@ -94,27 +99,21 @@ class WindowsSDKApi(recipe_api.RecipeApi): env = {} env_prefixes = {} - # Load .../win_sdk/bin/SetEnv.${arch}.json to extract the required - # environment. It contains a dict that looks like this: - # { - # "env": { - # "VAR": [["..", "..", "x"], ["..", "..", "y"]], - # ... - # } - # } - # All these environment variables need to be added to the environment - # for the compiler and linker to work. - assert target_arch in ('x86', 'x64') - filename = 'SetEnv.%s.json' % target_arch - step_result = self.m.json.read( - 'read %s' % filename, sdk_dir.join('win_sdk', 'bin', filename), - step_test_data=lambda: self.m.json.test_api.output({ - 'env': { - 'PATH': [['..', '..', 'win_sdk', 'bin', 'x64']], - 'VSINSTALLDIR': [['..', '..\\']], - }, - })) - data = step_result.json.output.get('env') + if target_arch not in ('x86', 'x64', 'arm64'): + raise ValueError('unknown architecture {!r}'.format(target_arch)) + + data = self.m.step('read SetEnv json', [ + 'python3', + self.resource('find_env_json.py'), '--sdk_root', sdk_dir, + '--target_arch', target_arch, + self.m.json.output() + ], + step_test_data=lambda: self.m.json.test_api.output({ + 'env': { + 'PATH': [['..', '..', 'win_sdk', 'bin', 'x64']], + 'VSINSTALLDIR': [['..', '..\\']], + }, + })).json.output.get('env') for key in data: # recipes' Path() does not like .., ., \, or /, so this is cumbersome. # What we want to do is: diff --git a/recipes/recipe_modules/windows_sdk/examples/full.expected/linux.json b/recipes/recipe_modules/windows_sdk/examples/full.expected/linux.json index 5b0f35212..ff5de65d2 100644 --- a/recipes/recipe_modules/windows_sdk/examples/full.expected/linux.json +++ b/recipes/recipe_modules/windows_sdk/examples/full.expected/linux.json @@ -15,6 +15,45 @@ ], "name": "ninja" }, + { + "cmd": [ + "cipd", + "ensure", + "-root", + "[CACHE]/windows_sdk", + "-ensure-file", + "chrome_internal/third_party/sdk/windows uploaded:2018-06-13", + "-max-threads", + "0", + "-json-output", + "/path/to/tmp/json" + ], + "infra_step": true, + "name": "ensure_installed", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@json.output@{@@@", + "@@@STEP_LOG_LINE@json.output@ \"result\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"\": [@@@", + "@@@STEP_LOG_LINE@json.output@ {@@@", + "@@@STEP_LOG_LINE@json.output@ \"instance_id\": \"resolved-instance_id-of-uploaded:2018-06\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"package\": \"chrome_internal/third_party/sdk/windows\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ ]@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@}@@@", + "@@@STEP_LOG_END@json.output@@@" + ] + }, + { + "cmd": [ + "taskkill.exe", + "/f", + "/t", + "/im", + "mspdbsrv.exe" + ], + "name": "taskkill mspdbsrv" + }, { "name": "$result" } diff --git a/recipes/recipe_modules/windows_sdk/examples/full.expected/mac.json b/recipes/recipe_modules/windows_sdk/examples/full.expected/mac.json index 5b0f35212..ff5de65d2 100644 --- a/recipes/recipe_modules/windows_sdk/examples/full.expected/mac.json +++ b/recipes/recipe_modules/windows_sdk/examples/full.expected/mac.json @@ -15,6 +15,45 @@ ], "name": "ninja" }, + { + "cmd": [ + "cipd", + "ensure", + "-root", + "[CACHE]/windows_sdk", + "-ensure-file", + "chrome_internal/third_party/sdk/windows uploaded:2018-06-13", + "-max-threads", + "0", + "-json-output", + "/path/to/tmp/json" + ], + "infra_step": true, + "name": "ensure_installed", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@json.output@{@@@", + "@@@STEP_LOG_LINE@json.output@ \"result\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"\": [@@@", + "@@@STEP_LOG_LINE@json.output@ {@@@", + "@@@STEP_LOG_LINE@json.output@ \"instance_id\": \"resolved-instance_id-of-uploaded:2018-06\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"package\": \"chrome_internal/third_party/sdk/windows\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ ]@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@}@@@", + "@@@STEP_LOG_END@json.output@@@" + ] + }, + { + "cmd": [ + "taskkill.exe", + "/f", + "/t", + "/im", + "mspdbsrv.exe" + ], + "name": "taskkill mspdbsrv" + }, { "name": "$result" } diff --git a/recipes/recipe_modules/windows_sdk/examples/full.expected/win.json b/recipes/recipe_modules/windows_sdk/examples/full.expected/win.json index a9f859347..4de24c915 100644 --- a/recipes/recipe_modules/windows_sdk/examples/full.expected/win.json +++ b/recipes/recipe_modules/windows_sdk/examples/full.expected/win.json @@ -30,13 +30,15 @@ }, { "cmd": [ - "python", - "-u", - "\nimport shutil\nimport sys\nshutil.copy(sys.argv[1], sys.argv[2])\n", - "[CACHE]\\windows_sdk\\win_sdk\\bin\\SetEnv.x64.json", + "python3", + "RECIPE_MODULE[depot_tools::windows_sdk]\\resources\\find_env_json.py", + "--sdk_root", + "[CACHE]\\windows_sdk", + "--target_arch", + "x64", "/path/to/tmp/json" ], - "name": "read SetEnv.x64.json", + "name": "read SetEnv json", "~followup_annotations": [ "@@@STEP_LOG_LINE@json.output@{@@@", "@@@STEP_LOG_LINE@json.output@ \"env\": {@@@", @@ -102,6 +104,45 @@ ], "name": "taskkill mspdbsrv" }, + { + "cmd": [ + "cipd.bat", + "ensure", + "-root", + "[CACHE]\\windows_sdk", + "-ensure-file", + "chrome_internal/third_party/sdk/windows uploaded:2018-06-13", + "-max-threads", + "0", + "-json-output", + "/path/to/tmp/json" + ], + "infra_step": true, + "name": "ensure_installed (2)", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@json.output@{@@@", + "@@@STEP_LOG_LINE@json.output@ \"result\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"\": [@@@", + "@@@STEP_LOG_LINE@json.output@ {@@@", + "@@@STEP_LOG_LINE@json.output@ \"instance_id\": \"resolved-instance_id-of-uploaded:2018-06\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"package\": \"chrome_internal/third_party/sdk/windows\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ ]@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@}@@@", + "@@@STEP_LOG_END@json.output@@@" + ] + }, + { + "cmd": [ + "taskkill.exe", + "/f", + "/t", + "/im", + "mspdbsrv.exe" + ], + "name": "taskkill mspdbsrv (2)" + }, { "name": "$result" } diff --git a/recipes/recipe_modules/windows_sdk/examples/full.py b/recipes/recipe_modules/windows_sdk/examples/full.py index 64648f20e..e3792597b 100644 --- a/recipes/recipe_modules/windows_sdk/examples/full.py +++ b/recipes/recipe_modules/windows_sdk/examples/full.py @@ -17,6 +17,13 @@ def RunSteps(api): api.step('gn', ['gn', 'gen', 'out/Release']) api.step('ninja', ['ninja', '-C', 'out/Release']) + # bad arch + try: + with api.windows_sdk(target_arch='lolnope'): + assert False, "never here" # pragma: no cover + except ValueError: + pass + def GenTests(api): for platform in ('linux', 'mac', 'win'): diff --git a/recipes/recipe_modules/windows_sdk/resources/find_env_json.py b/recipes/recipe_modules/windows_sdk/resources/find_env_json.py new file mode 100755 index 000000000..70dc1af6b --- /dev/null +++ b/recipes/recipe_modules/windows_sdk/resources/find_env_json.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# Copyright 2021 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +""" +This script finds the SetEnv.*.json file from an unpacked Windows SDK. +""" + +import argparse +import os +import sys + +POSSIBLE_BASE_LOCATIONS = [ + # Older SDKs just used the raw 'bin' directory + os.path.join("win_sdk", "bin"), + + # SDK versions after 19041 + os.path.join("win_sdk", "Windows Kits", "10", "bin"), +] + +SDK_ARCHITECTURES = frozenset([ + "x86", + "x64", + "arm64", +]) + + +def main(): + parser = argparse.ArgumentParser( + description='Find the SetEnv from a windows SDK') + parser.add_argument('--sdk_root', + metavar='PATH', + required=True, + help='The absolute path to the root of the unpacked SDK') + parser.add_argument('--target_arch', + choices=SDK_ARCHITECTURES, + required=True, + help='The target architecture') + parser.add_argument('--output_json', + required=True, + help='The absolute path to an output json file') + args = parser.parse_args() + + if not os.path.isabs(args.sdk_root): + parser.error("sdk_root must be absolute, got {!r}".format(args.sdk_root)) + + if not os.path.isabs(args.output_json): + parser.error("output_json must be absolute, got {!r}".format( + args.output_json)) + + with open(args.output_json, 'w', encoding="utf-8") as outf: + tail = "SetEnv.{}.json".format(args.target_arch) + for loc in POSSIBLE_BASE_LOCATIONS: + full = os.path.join(args.sdk_root, loc, tail) + print("Attempting:", full) + try: + with open(full, encoding="utf-8") as set_env_json: + print("> Found it!") + outf.write(set_env_json.read()) + return + except OSError as ex: + print("> Failed:", ex) + continue + + print("Unable to locate SetEnv file") + sys.exit(1) + + +if __name__ == '__main__': + main()