• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2024 - The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the',  help='License');
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an',  help='AS IS' BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14from collections import UserDict
15import json
16import logging
17import os
18from pathlib import Path
19import platform
20import subprocess
21
22
23class BaseEnvironment(UserDict):
24  """Base class for environment management, providing a common foundation for
25
26  both Posix and Windows environments.
27  """
28
29  def __init__(self, aosp: Path):
30    super().__init__({
31        "PATH": (
32            str(
33                aosp
34                / "external"
35                / "qemu"
36                / "android"
37                / "third_party"
38                / "chromium"
39                / "depot_tools"
40            )
41            + os.pathsep
42            + os.environ.get("PATH", "")
43        )
44    })
45
46
47class PosixEnvironment(BaseEnvironment):
48
49  def __init__(self, aosp: Path):
50    super().__init__(aosp)
51
52
53class VisualStudioNotFoundException(Exception):
54  pass
55
56
57class VisualStudioMissingVarException(Exception):
58  pass
59
60
61class VisualStudioNativeWorkloadNotFoundException(Exception):
62  pass
63
64
65class WindowsEnvironment(BaseEnvironment):
66  """Environment manager for Windows systems, specifically handling Visual Studio integration."""
67
68  def __init__(self, aosp: Path):
69    assert platform.system() == "Windows"
70    super().__init__(aosp)
71    for key in os.environ:
72      self[key.upper()] = os.environ[key]
73
74    vs = self._visual_studio()
75    logging.info("Loading environment from %s", vs)
76    env_lines = subprocess.check_output(
77        [vs, "&&", "set"], encoding="utf-8"
78    ).splitlines()
79    for line in env_lines:
80      if "=" in line:
81        key, val = line.split("=", 1)
82        # Variables in windows are case insensitive, but not in python dict!
83        self[key.upper()] = val
84
85    # Set PYTHONUTF8 to 1
86    self["PYTHONUTF8"] = "1"
87
88    if not "VSINSTALLDIR" in self:
89      raise VisualStudioMissingVarException(
90          "Missing VSINSTALLDIR in environment"
91      )
92
93    if not "VCTOOLSINSTALLDIR" in self:
94      raise VisualStudioMissingVarException(
95          "Missing VCTOOLSINSTALLDIR in environment"
96      )
97
98  def _visual_studio(self) -> Path:
99    """Locates the Visual Studio installation and its Native Desktop workload.
100
101    Raises:
102        VisualStudioNotFoundException: When Visual Studio is not found.
103        VisualStudioNativeWorkloadNotFoundException: When the Native Desktop
104        workload is not found.
105
106    Returns:
107        Path: Path to the Visual Studio vcvars64.bat file.
108    """
109    prgrfiles = Path(os.getenv("ProgramFiles(x86)", "C:\Program Files (x86)"))
110    res = subprocess.check_output([
111        str(
112            prgrfiles / "Microsoft Visual Studio" / "Installer" / "vswhere.exe"
113        ),
114        "-requires",
115        "Microsoft.VisualStudio.Workload.NativeDesktop",
116        "-sort",
117        "-format",
118        "json",
119        "-utf8",
120    ])
121    vsresult = json.loads(res)
122    if len(vsresult) == 0:
123      raise VisualStudioNativeWorkloadNotFoundException(
124          "No visual studio with the native desktop load available."
125      )
126
127    for install in vsresult:
128      logging.debug("Considering %s", install["displayName"])
129      candidates = list(
130          Path(install["installationPath"]).glob("**/vcvars64.bat")
131      )
132
133      if len(candidates) > 0:
134        return candidates[0].absolute()
135
136    # Oh oh, no visual studio..
137    raise VisualStudioNotFoundException(
138        "Unable to detect a visual studio installation with the native desktop"
139        " workload."
140    )
141
142
143def get_default_environment(aosp: Path):
144  """Returns the appropriate environment manager based on the current operating system.
145
146  The environment will make sure the following things hold:
147
148  - Ninja will be on the PATH
149  - The visual studio tools environment will be loaded
150  """
151  if platform.system() == "Windows":
152    return WindowsEnvironment(aosp)
153  return PosixEnvironment(aosp)
154