• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
2# Copyright (C) 2022 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import json
17import os
18import sys
19
20import ninja_tools
21import ninja_syntax  # Has to be after ninja_tools because of the path hack
22
23
24def final_packaging(context, inner_trees):
25    """Pull together all of the previously defined rules into the final build stems."""
26
27    with open(context.out.outer_ninja_file(), "w",
28              encoding='iso-8859-1') as ninja_file:
29        ninja = ninja_tools.Ninja(context, ninja_file)
30
31        # Add the api surfaces file
32        ninja.add_subninja(
33            ninja_syntax.Subninja(
34                context.out.api_ninja_file(base=context.out.Base.OUTER)))
35
36        # For each inner tree
37        for tree in inner_trees.keys():
38            # TODO: Verify that inner_tree.ninja was generated
39
40            # Read and verify file
41            build_targets = read_build_targets_json(context, tree)
42            if not build_targets:
43                continue
44
45            # Generate the ninja and build files for this inner tree
46            generate_cross_domain_build_rules(context, ninja, tree,
47                                              build_targets)
48
49        # Finish writing the ninja file
50        ninja.write()
51
52
53def read_build_targets_json(context, tree):
54    """Read and validate the build_targets.json file for the given tree."""
55    try:
56        f = open(tree.out.build_targets_file(), encoding='iso-8859-1')
57    except FileNotFoundError:
58        # It's allowed not to have any artifacts (e.g. if a tree is a light tree with only APIs)
59        return None
60
61    data = None
62    with f:
63        try:
64            data = json.load(f)
65        except json.decoder.JSONDecodeError as ex:
66            sys.stderr.write("Error parsing file: %s\n" %
67                             tree.out.build_targets_file())
68            # TODO: Error reporting
69            raise ex
70
71    # TODO: Better error handling
72    # TODO: Validate json schema
73    return data
74
75
76def generate_cross_domain_build_rules(context, ninja, tree, build_targets):
77    "Generate the ninja and build files for the inner tree."
78    # Include the inner tree's inner_tree.ninja
79    ninja.add_subninja(
80        ninja_syntax.Subninja(
81            tree.out.main_ninja_file(base=tree.out.Base.OUTER),
82            chdir=tree.root,
83            env_vars=tree.env_used))
84
85    # Generate module rules and files
86    for module in build_targets.get("modules", []):
87        generate_shared_module(context, ninja, tree, module)
88
89    # Generate staging rules
90    staging_dir = context.out.staging_dir(base=context.out.Base.OUTER)
91    for staged in build_targets.get("staging", []):
92        # TODO: Enforce that dest isn't in disallowed subdir of out or absolute
93        dest = staged["dest"]
94        dest = os.path.join(staging_dir, dest)
95        if "src" in staged and "obj" in staged:
96            context.errors.error(
97                "Can't have both \"src\" and \"obj\" tags in \"staging\" entry."
98            )  # TODO: Filename and line if possible
99        if "src" in staged:
100            ninja.add_copy_file(dest, os.path.join(tree.root, staged["src"]))
101        elif "obj" in staged:
102            ninja.add_copy_file(
103                dest,
104                os.path.join(tree.out.root(base=tree.out.Base.OUTER),
105                             staged["obj"]))
106        ninja.add_global_phony("staging", [dest])
107
108    # Generate dist rules
109    dist_dir = context.out.dist_dir(base=context.out.Base.OUTER)
110    for disted in build_targets.get("dist", []):
111        # TODO: Enforce that dest absolute
112        dest = disted["dest"]
113        dest = os.path.join(dist_dir, dest)
114        ninja.add_copy_file(dest, os.path.join(tree.root, disted["src"]))
115        ninja.add_global_phony("dist", [dest])
116
117
118def generate_shared_module(context, ninja, tree, module):
119    """Generate ninja rules for the given build_targets.json defined module."""
120    module_name = module["name"]
121    module_type = module["type"]
122    share_dir = context.out.module_share_dir(module_type,
123                                             module_name,
124                                             base=context.out.Base.OUTER)
125    src_file = os.path.join(tree.root, module["file"])
126
127    if module_type == "apex":
128        ninja.add_copy_file(os.path.join(share_dir, module_name + ".apex"),
129                            src_file)
130        # TODO: Generate build file
131
132    else:
133        # TODO: Better error handling
134        raise Exception("Invalid module type: %s" % module)
135