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