Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14c84a2d authored by Joe Onorato's avatar Joe Onorato Committed by Automerger Merge Worker
Browse files

Merge "Generate ninja files for api assembly and run ninja." am: 9327b9cb

parents c7638c66 9327b9cb
Loading
Loading
Loading
Loading
+43 −39
Original line number Diff line number Diff line
@@ -14,11 +14,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import collections
import json
import os
import sys

def assemble_apis(inner_trees):
import api_assembly_cc
import ninja_tools


ContributionData = collections.namedtuple("ContributionData", ("inner_tree", "json_data"))

def assemble_apis(context, inner_trees):
    # Find all of the contributions from the inner tree
    contribution_files_dict = inner_trees.for_each_tree(api_contribution_files_for_inner_tree)

@@ -27,26 +34,34 @@ def assemble_apis(inner_trees):
    contributions = []
    for tree_key, filenames in contribution_files_dict.items():
        for filename in filenames:
            contribution_data = load_contribution_file(filename)
            if not contribution_data:
            json_data = load_contribution_file(filename)
            if not json_data:
                continue
            # TODO: Validate the configs, especially that the domains match what we asked for
            # from the lunch config.
            contributions.append(contribution_data)
            contributions.append(ContributionData(inner_trees.get(tree_key), json_data))

    # Group contributions by language and API surface
    stub_libraries = collate_contributions(contributions)

    # Initialize the ninja file writer
    with open(context.out.api_ninja_file(), "w") as ninja_file:
        ninja = ninja_tools.Ninja(context, ninja_file)

        # Initialize the build file writer
        build_file = BuildFile() # TODO: parameters?

        # Iterate through all of the stub libraries and generate rules to assemble them
        # and Android.bp/BUILD files to make those available to inner trees.
        # TODO: Parallelize? Skip unnecessary work?
    ninja_file = NinjaFile() # TODO: parameters?
    build_file = BuildFile() # TODO: parameters?
        for stub_library in stub_libraries:
        STUB_LANGUAGE_HANDLERS[stub_library.language](ninja_file, build_file, stub_library)
            STUB_LANGUAGE_HANDLERS[stub_library.language](context, ninja, build_file, stub_library)

        # TODO: Handle host_executables separately or as a StubLibrary language?

        # Finish writing the ninja file
        ninja.write()


def api_contribution_files_for_inner_tree(tree_key, inner_tree, cookie):
    "Scan an inner_tree's out dir for the api contribution files."
@@ -72,7 +87,8 @@ def load_contribution_file(filename):


class StubLibraryContribution(object):
    def __init__(self, api_domain, library_contribution):
    def __init__(self, inner_tree, api_domain, library_contribution):
        self.inner_tree = inner_tree
        self.api_domain = api_domain
        self.library_contribution = library_contribution

@@ -96,54 +112,42 @@ def collate_contributions(contributions):
    grouped = {}
    for contribution in contributions:
        for language in STUB_LANGUAGE_HANDLERS.keys():
            for library in contribution.get(language, []):
                key = (language, contribution["name"], contribution["version"], library["name"])
            for library in contribution.json_data.get(language, []):
                key = (language, contribution.json_data["name"],
                        contribution.json_data["version"], library["name"])
                stub_library = grouped.get(key)
                if not stub_library:
                    stub_library = StubLibrary(language, contribution["name"],
                            contribution["version"], library["name"])
                    stub_library = StubLibrary(language, contribution.json_data["name"],
                            contribution.json_data["version"], library["name"])
                    grouped[key] = stub_library
                stub_library.add_contribution(StubLibraryContribution(
                        contribution["api_domain"], library))
                stub_library.add_contribution(StubLibraryContribution(contribution.inner_tree,
                        contribution.json_data["api_domain"], library))
    return list(grouped.values())


def assemble_cc_api_library(ninja_file, build_file, stub_library):
    print("assembling cc_api_library %s-%s %s from:" % (stub_library.api_surface, stub_library.api_surface_version,
            stub_library.name))
def assemble_java_api_library(context, ninja, build_file, stub_library):
    print("assembling java_api_library %s-%s %s from:" % (stub_library.api_surface,
            stub_library.api_surface_version, stub_library.name))
    for contrib in stub_library.contributions:
        print("  %s %s" % (contrib.api_domain, contrib.library_contribution["api"]))
    # TODO: Implement me


def assemble_java_api_library(ninja_file, build_file, stub_library):
    print("assembling java_api_library %s-%s %s from:" % (stub_library.api_surface, stub_library.api_surface_version,
            stub_library.name))
    for contrib in stub_library.contributions:
        print("  %s %s" % (contrib.api_domain, contrib.library_contribution["api"]))
    # TODO: Implement me


def assemble_resource_api_library(ninja_file, build_file, stub_library):
    print("assembling resource_api_library %s-%s %s from:" % (stub_library.api_surface, stub_library.api_surface_version,
            stub_library.name))
def assemble_resource_api_library(context, ninja, build_file, stub_library):
    print("assembling resource_api_library %s-%s %s from:" % (stub_library.api_surface,
            stub_library.api_surface_version, stub_library.name))
    for contrib in stub_library.contributions:
        print("  %s %s" % (contrib.api_domain, contrib.library_contribution["api"]))
    # TODO: Implement me


STUB_LANGUAGE_HANDLERS = {
    "cc_libraries": assemble_cc_api_library,
    "cc_libraries": api_assembly_cc.assemble_cc_api_library,
    "java_libraries": assemble_java_api_library,
    "resource_libraries": assemble_resource_api_library,
}


class NinjaFile(object):
    "Generator for build actions and dependencies."
    pass


class BuildFile(object):
    "Abstract generator for Android.bp files and BUILD files."
    pass
+55 −0
Original line number Diff line number Diff line
#!/usr/bin/python3
#
# Copyright (C) 2022 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os

def assemble_cc_api_library(context, ninja, build_file, stub_library):
    print("\nassembling cc_api_library %s-%s %s from:" % (stub_library.api_surface,
        stub_library.api_surface_version, stub_library.name))
    for contrib in stub_library.contributions:
        print("  %s %s" % (contrib.api_domain, contrib.library_contribution))

    staging_dir = context.out.api_library_dir(stub_library.api_surface,
            stub_library.api_surface_version, stub_library.name)
    work_dir = context.out.api_library_work_dir(stub_library.api_surface,
            stub_library.api_surface_version, stub_library.name)
    print("staging_dir=%s" % (staging_dir))
    print("work_dir=%s" % (work_dir))

    # Generate rules to copy headers
    includes = []
    include_dir = os.path.join(staging_dir, "include")
    for contrib in stub_library.contributions:
        for headers in contrib.library_contribution["headers"]:
            root = headers["root"]
            for file in headers["files"]:
                # TODO: Deal with collisions of the same name from multiple contributions
                include = os.path.join(include_dir, file)
                ninja.add_copy_file(include, os.path.join(contrib.inner_tree.root, root, file))
                includes.append(include)

    # Generate rule to run ndkstubgen


    # Generate rule to compile stubs to library

    # Generate phony rule to build the library
    # TODO: This name probably conflictgs with something
    ninja.add_phony("-".join((stub_library.api_surface, str(stub_library.api_surface_version),
            stub_library.name)), includes)

    # Generate build files
+29 −0
Original line number Diff line number Diff line
#
# Copyright (C) 2022 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import ninja_tools
import ninja_syntax # Has to be after ninja_tools because of the path hack

def final_packaging(context):
    """Pull together all of the previously defined rules into the final build stems."""

    with open(context.out.outer_ninja_file(), "w") as ninja_file:
        ninja = ninja_tools.Ninja(context, ninja_file)

        # Add the api surfaces file
        ninja.add_subninja(ninja_syntax.Subninja(context.out.api_ninja_file(), chDir=None))

        # Finish writing the ninja file
        ninja.write()
+9 −2
Original line number Diff line number Diff line
@@ -56,13 +56,13 @@ class InnerTreeKey(object):


class InnerTree(object):
    def __init__(self, root, product):
    def __init__(self, context, root, product):
        """Initialize with the inner tree root (relative to the workspace root)"""
        self.root = root
        self.product = product
        self.domains = {}
        # TODO: Base directory on OUT_DIR
        self.out = OutDirLayout(os.path.join("out", "trees", root))
        self.out = OutDirLayout(context.out.inner_tree_dir(root))

    def __str__(self):
        return "InnerTree(root=%s product=%s domains=[%s])" % (enquote(self.root),
@@ -134,7 +134,14 @@ class InnerTrees(object):
        return result


    def get(self, tree_key):
        """Get an inner tree for tree_key"""
        return self.trees.get(tree_key)

class OutDirLayout(object):
    """Encapsulates the logic about the layout of the inner tree out directories.
    See also context.OutDir for outer tree out dir contents."""

    def __init__(self, root):
        "Initialize with the root of the OUT_DIR for the inner tree."
        self._root = root
+36 −0
Original line number Diff line number Diff line
#
# Copyright (C) 2022 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import subprocess

def run_ninja(context, targets):
    """Run ninja.
    """

    # Construct the command
    cmd = [
            context.tools.ninja(),
            "-f",
            context.out.outer_ninja_file(),
        ] + targets

    # Run the command
    process = subprocess.run(cmd, shell=False)

    # TODO: Probably want better handling of inner tree failures
    if process.returncode:
        sys.stderr.write("Build error in outer tree.\nstopping multitree build.\n")
        sys.exit(1)
Loading