mozangle 0.3.6

Mozilla’s fork of Google ANGLE, repackaged as a Rust crate
Documentation
#!/usr/bin/env python3

from os import path

REPO = path.dirname(__file__)
ANGLE = path.join(REPO, "gfx", "angle")

def run():
    data = {}
    for lib in ["translator", "libANGLE", "libEGL", "libGLESv2"]:
        data[lib] = {
            "DEFINES": {},
            "LOCAL_INCLUDES": [],
            "SOURCES": [],
            "USE_LIBS": [],
            "OS_LIBS": [],
        }
        directory = path.join(ANGLE, "targets", lib)
        parse_lib(directory, data[lib])
        parse_lib(ANGLE, data[lib], ".common")

    # Remove duplicate source files from libEGL and libGLESv2 since
    # they are included in libANGLE and will be statically linked in.
    def remove_duplicates_source_files(from_data: list[str]):
        from_data['SOURCES'] = [
            file for file in from_data['SOURCES']
                if file not in data['libANGLE']['SOURCES']]

    remove_duplicates_source_files(data['libEGL'])
    remove_duplicates_source_files(data['libGLESv2'])

    with open(path.join(REPO, "build_data.rs"), "wb") as f:
        write(data, f)

def parse_lib(directory, data, suffix=""):
    mozbuild = path.join(directory, "moz.build" + suffix)
    env = {
        "include": noop,
        "Library": noop,
        "GeckoSharedLibrary": noop,
        "AllowCompilerWarnings": noop,
        "SRCDIR": directory,
        "CXXFLAGS": "",
        "DIRS": [],
        "CONFIG": {
            "SSE2_FLAGS": "",
            "OS_ARCH": "neither",
            "INTEL_ARCHITECTURE": "Yes",
        },
    }
    env.update(data)
    with open(mozbuild) as f:
        code = compile(f.read(), mozbuild, "exec")
        exec(code, env, env)
    for dir in env["DIRS"]:
        prefix = "../"
        assert dir.startswith(prefix)
        directory = path.join(ANGLE, "targets", dir[len(prefix):])
        parse_lib(directory, data)

def noop(*_args, **_kwargs):
    pass

def write(data, f):
    f.write(
        b"// Generated from gfx/angle/**/moz.build by generate_build_data.py\n"
        b"// Do not edit directly. Instead, edit and run generate_build_data.py again.\n"
        b"\n"
        b"pub struct Data {\n"
        b"     pub sources: &'static [&'static str],\n"
        b"     pub includes: &'static [&'static str],\n"
        b"     pub defines: &'static [(&'static str, Option<&'static str>)],\n"
        b"     pub os_libs: &'static [&'static str],\n"
        b"}\n"
        b"\n"
    )
    write_lib(b"TRANSLATOR", data["translator"], f)
    write_lib(b"ANGLE", data["libANGLE"], f)
    write_lib(b"EGL", data["libEGL"], f)
    write_lib(b"GLESv2", data["libGLESv2"], f)

def no_platform_sources(source):
    # Filter out any accidental inclusion of platform-specific source files.
    return "system_utils_posix.cpp" not in source and "system_utils_linux.cpp" not in source

def write_lib(name, data, f):
    defines = [
        b"(%s, %s)" % (
            string_literal(k),
            b"None" if v is True else b"Some(%s)" % string_literal(v)
        )
        for k, v in data["DEFINES"].items()
    ]

    f.write(b"pub const %s: Data = Data {\n" % name)
    write_list(b"sources", map(string_literal, filter(no_platform_sources, data["SOURCES"])), f)
    write_list(b"includes", map(string_literal, data["LOCAL_INCLUDES"]), f)
    write_list(b"defines", defines, f)
    write_list(b"os_libs", map(string_literal, data["OS_LIBS"]), f)
    f.write(b"};\n")

def string_literal(s):
    prelen = 1
    raw = repr(s).replace('"', '\\"')
    return b"\"%s\"" % raw[prelen:-prelen].encode("utf-8")

def write_list(name, items, f):
    items = sorted(set(items))
    f.write(b"    %s: &[\n" % name)
    for item in items:
        f.write(b"        %s,\n" % item)
    f.write(b"    ],\n")

if __name__ == '__main__':
    run()