xref: /aosp_15_r20/development/tools/ndk/ndkabidump/soong.py (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1*90c8c64dSAndroid Build Coastguard Worker#
2*90c8c64dSAndroid Build Coastguard Worker# Copyright (C) 2021 The Android Open Source Project
3*90c8c64dSAndroid Build Coastguard Worker#
4*90c8c64dSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*90c8c64dSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*90c8c64dSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*90c8c64dSAndroid Build Coastguard Worker#
8*90c8c64dSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*90c8c64dSAndroid Build Coastguard Worker#
10*90c8c64dSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*90c8c64dSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*90c8c64dSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*90c8c64dSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*90c8c64dSAndroid Build Coastguard Worker# limitations under the License.
15*90c8c64dSAndroid Build Coastguard Worker#
16*90c8c64dSAndroid Build Coastguard Worker"""APIs for interacting with Soong."""
17*90c8c64dSAndroid Build Coastguard Workerimport logging
18*90c8c64dSAndroid Build Coastguard Workerimport os
19*90c8c64dSAndroid Build Coastguard Workerfrom pathlib import Path
20*90c8c64dSAndroid Build Coastguard Workerimport shlex
21*90c8c64dSAndroid Build Coastguard Workerimport shutil
22*90c8c64dSAndroid Build Coastguard Workerimport subprocess
23*90c8c64dSAndroid Build Coastguard Worker
24*90c8c64dSAndroid Build Coastguard Worker
25*90c8c64dSAndroid Build Coastguard Workerdef logger() -> logging.Logger:
26*90c8c64dSAndroid Build Coastguard Worker    """Returns the module level logger."""
27*90c8c64dSAndroid Build Coastguard Worker    return logging.getLogger(__name__)
28*90c8c64dSAndroid Build Coastguard Worker
29*90c8c64dSAndroid Build Coastguard Worker
30*90c8c64dSAndroid Build Coastguard Workerclass Soong:
31*90c8c64dSAndroid Build Coastguard Worker    """Interface for interacting with Soong."""
32*90c8c64dSAndroid Build Coastguard Worker
33*90c8c64dSAndroid Build Coastguard Worker    def __init__(self, build_top: Path, out_dir: Path) -> None:
34*90c8c64dSAndroid Build Coastguard Worker        self.out_dir = out_dir
35*90c8c64dSAndroid Build Coastguard Worker        self.soong_ui_path = build_top / "build/soong/soong_ui.bash"
36*90c8c64dSAndroid Build Coastguard Worker
37*90c8c64dSAndroid Build Coastguard Worker    def soong_ui(
38*90c8c64dSAndroid Build Coastguard Worker        self,
39*90c8c64dSAndroid Build Coastguard Worker        args: list[str],
40*90c8c64dSAndroid Build Coastguard Worker        env: dict[str, str] | None = None,
41*90c8c64dSAndroid Build Coastguard Worker        capture_output: bool = False,
42*90c8c64dSAndroid Build Coastguard Worker    ) -> str:
43*90c8c64dSAndroid Build Coastguard Worker        """Executes soong_ui.bash and returns the output on success.
44*90c8c64dSAndroid Build Coastguard Worker
45*90c8c64dSAndroid Build Coastguard Worker        Args:
46*90c8c64dSAndroid Build Coastguard Worker            args: List of string arguments to pass to soong_ui.bash.
47*90c8c64dSAndroid Build Coastguard Worker            env: Additional environment variables to set when running soong_ui.
48*90c8c64dSAndroid Build Coastguard Worker            capture_output: True if the output of the command should be captured and
49*90c8c64dSAndroid Build Coastguard Worker                returned. If not, the output will be printed to stdout/stderr and an
50*90c8c64dSAndroid Build Coastguard Worker                empty string will be returned.
51*90c8c64dSAndroid Build Coastguard Worker
52*90c8c64dSAndroid Build Coastguard Worker        Raises:
53*90c8c64dSAndroid Build Coastguard Worker            subprocess.CalledProcessError: The subprocess failure if the soong command
54*90c8c64dSAndroid Build Coastguard Worker            failed.
55*90c8c64dSAndroid Build Coastguard Worker
56*90c8c64dSAndroid Build Coastguard Worker        Returns:
57*90c8c64dSAndroid Build Coastguard Worker            The interleaved contents of stdout/stderr if capture_output is True, else an
58*90c8c64dSAndroid Build Coastguard Worker            empty string.
59*90c8c64dSAndroid Build Coastguard Worker        """
60*90c8c64dSAndroid Build Coastguard Worker        if env is None:
61*90c8c64dSAndroid Build Coastguard Worker            env = {}
62*90c8c64dSAndroid Build Coastguard Worker
63*90c8c64dSAndroid Build Coastguard Worker        # Use a (mostly) clean environment to avoid the caller's lunch
64*90c8c64dSAndroid Build Coastguard Worker        # environment affecting the build.
65*90c8c64dSAndroid Build Coastguard Worker        exec_env = {
66*90c8c64dSAndroid Build Coastguard Worker            # Newer versions of golang require the go cache, which defaults to somewhere
67*90c8c64dSAndroid Build Coastguard Worker            # in HOME if not set.
68*90c8c64dSAndroid Build Coastguard Worker            "HOME": os.environ["HOME"],
69*90c8c64dSAndroid Build Coastguard Worker            "OUT_DIR": str(self.out_dir.resolve()),
70*90c8c64dSAndroid Build Coastguard Worker            "PATH": os.environ["PATH"],
71*90c8c64dSAndroid Build Coastguard Worker        }
72*90c8c64dSAndroid Build Coastguard Worker        exec_env.update(env)
73*90c8c64dSAndroid Build Coastguard Worker        env_prefix = " ".join(f"{k}={v}" for k, v in exec_env.items())
74*90c8c64dSAndroid Build Coastguard Worker        cmd = [str(self.soong_ui_path)] + args
75*90c8c64dSAndroid Build Coastguard Worker        logger().debug(f"running in {os.getcwd()}: {env_prefix} {shlex.join(cmd)}")
76*90c8c64dSAndroid Build Coastguard Worker        result = subprocess.run(
77*90c8c64dSAndroid Build Coastguard Worker            cmd,
78*90c8c64dSAndroid Build Coastguard Worker            check=True,
79*90c8c64dSAndroid Build Coastguard Worker            capture_output=capture_output,
80*90c8c64dSAndroid Build Coastguard Worker            encoding="utf-8",
81*90c8c64dSAndroid Build Coastguard Worker            env=exec_env,
82*90c8c64dSAndroid Build Coastguard Worker        )
83*90c8c64dSAndroid Build Coastguard Worker        return result.stdout
84*90c8c64dSAndroid Build Coastguard Worker
85*90c8c64dSAndroid Build Coastguard Worker    def get_make_var(self, name: str) -> str:
86*90c8c64dSAndroid Build Coastguard Worker        """Queries the build system for the value of a make variable.
87*90c8c64dSAndroid Build Coastguard Worker
88*90c8c64dSAndroid Build Coastguard Worker        Args:
89*90c8c64dSAndroid Build Coastguard Worker            name: The name of the build variable to query.
90*90c8c64dSAndroid Build Coastguard Worker
91*90c8c64dSAndroid Build Coastguard Worker        Returns:
92*90c8c64dSAndroid Build Coastguard Worker            The value of the build variable in string form.
93*90c8c64dSAndroid Build Coastguard Worker        """
94*90c8c64dSAndroid Build Coastguard Worker        return self.soong_ui(["--dumpvar-mode", name], capture_output=True).rstrip("\n")
95*90c8c64dSAndroid Build Coastguard Worker
96*90c8c64dSAndroid Build Coastguard Worker    def clean(self) -> None:
97*90c8c64dSAndroid Build Coastguard Worker        """Removes the output directory, if it exists."""
98*90c8c64dSAndroid Build Coastguard Worker        if self.out_dir.exists():
99*90c8c64dSAndroid Build Coastguard Worker            shutil.rmtree(self.out_dir)
100*90c8c64dSAndroid Build Coastguard Worker
101*90c8c64dSAndroid Build Coastguard Worker    def build(self, targets: list[str], env: dict[str, str] | None = None) -> None:
102*90c8c64dSAndroid Build Coastguard Worker        """Builds the given targets.
103*90c8c64dSAndroid Build Coastguard Worker
104*90c8c64dSAndroid Build Coastguard Worker        The out directory will be created if it does not already exist. Existing
105*90c8c64dSAndroid Build Coastguard Worker        contents will not be removed, but affected outputs will be modified.
106*90c8c64dSAndroid Build Coastguard Worker
107*90c8c64dSAndroid Build Coastguard Worker        Args:
108*90c8c64dSAndroid Build Coastguard Worker            targets: A list of target names to build.
109*90c8c64dSAndroid Build Coastguard Worker            env: Additional environment variables to set when running the build.
110*90c8c64dSAndroid Build Coastguard Worker        """
111*90c8c64dSAndroid Build Coastguard Worker        self.out_dir.mkdir(parents=True, exist_ok=True)
112*90c8c64dSAndroid Build Coastguard Worker        self.soong_ui(["--make-mode", "--soong-only"] + targets, env=env)
113