• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (C) 2022 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "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 "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.
14
15import collections
16import os
17import sys
18
19# Workaround for python include path
20# TODO: restructure things so that we do not need this.
21# pylint: disable=wrong-import-position,import-error
22_ninja_dir = os.path.realpath(
23    os.path.join(os.path.dirname(__file__), "..", "ninja"))
24if _ninja_dir not in sys.path:
25    sys.path.append(_ninja_dir)
26import ninja_writer
27from ninja_syntax import BuildAction, Rule
28# pylint: enable=wrong-import-position,import-error
29
30
31class Ninja(ninja_writer.Writer):
32    """Some higher level constructs on top of raw ninja writing.
33
34    TODO: Not sure where these should be.
35    """
36
37    def __init__(self, context, file, **kwargs):
38        super().__init__(
39            file,
40            builddir=context.out.root(base=context.out.Base.OUTER),
41            **kwargs)
42        self._context = context
43        self._did_copy_file = False
44        self._write_rule = None
45        self._phonies = collections.defaultdict(set)
46        self._acp = self._context.tools.acp()
47
48    def add_copy_file(self, copy_to, copy_from):
49        self.add_rule(
50            Rule("copy_file", [
51                ("command",
52                 f"mkdir -p ${{out_dir}} && {self._acp} -f ${{in}} ${{out}}")
53            ]))
54        self.add_build_action(
55            BuildAction(output=copy_to,
56                        rule="copy_file",
57                        inputs=[copy_from],
58                        implicits=[self._acp],
59                        variables=[("out_dir", os.path.dirname(copy_to))]))
60
61    def add_global_phony(self, name, deps):
62        """Add a global phony target.
63
64        This should be used when there are multiple places that will want to add
65        to the same phony, with possibly different dependencies. The resulting
66        dependency list will be the combined dependency list.
67
68        If you can, to save memory, use add_phony instead of this function.
69        """
70        assert isinstance(deps, (set, list, tuple)), f"bad type: {type(deps)}"
71        self._phonies[name] |= set(deps)
72
73    def write(self, *args, **kwargs):
74        """Write the file, including our global phonies."""
75        for phony, deps in self._phonies.items():
76            self.add_phony(phony, deps)
77        super().write(*args, **kwargs)
78
79    def add_write_file(self, filepath: str, content: str):
80        """Writes the content as a string to filepath
81
82        The content is written as-is, special characters are not escaped
83        """
84        self.add_rule(
85            Rule("write_file", [("description", "Writes content to out"),
86                                ("command", "printf '${content}' > ${out}")]))
87
88        self.add_build_action(
89            BuildAction(output=filepath,
90                        rule="write_file",
91                        variables=[("content", content)]))
92