#!/usr/bin/env python3
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
import argparse
import re
import util
import parse_specs
import generate_code
import generate_docs
import os
import sys
import platform
import time
import subprocess
from version import Version
def add_argument(parser, name, help, default=False):
"""
helper for adding mutually-exclusive boolean arguments "--name" and "--!name"
"""
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument(
"--" + name, dest=name, help="Enable " + help, action="store_true"
)
group.add_argument(
"--!" + name, dest=name, help="Disable " + help, action="store_false"
)
parser.set_defaults(**{name: default})
def clean():
"""helper for cleaning previously generated files"""
util.removePath("../include")
util.makePath("../include")
util.removePath("../build")
util.makePath("../build")
def update_spec(target):
"""help for updating spec documentation"""
inc = "%s/source/elements/l0/include" % target
src = "%s/source/elements/l0/source" % target
util.copyTree("../include", inc)
util.copyTree("../docs/source", src)
util.removePath("%s/experimental" % inc)
util.removePath("%s/experimental" % src)
def build():
"""helper for running cmake windows build"""
if "Windows" == platform.system():
result = os.system('cmake -B ../build/ -S .. -G "Visual Studio 16 2019" -A x64')
else:
result = -1 # todo
if result == 0:
result = os.system("cmake --build ../build --clean-first")
return result == 0
def revision():
"""
helper for getting revision number from git repository
revision is number of commits since tag 'v0'
"""
return "0"
result = subprocess.run(
["git", "describe", "--tags", "--dirty"],
cwd=os.path.dirname(os.path.abspath(__file__)),
stdout=subprocess.PIPE,
)
if result.returncode:
print("ERROR: Could not get revision number from git", file=sys.stderr)
return "0"
items = result.stdout.decode().strip().split("-")
tag = items[0][1:] # remove 'v'
print("Version is %s" % tag)
count = 0
if len(items) > 1 and items[1].isdigit():
count = int(items[1])
# Bump count if any local files are dirty.
# Keeps the count the same after doing a commit (assuming all dirty files are committed)
if "dirty" in items[-1]:
count += 1
return "%s.%s" % (tag, count)
def get_version_from_cmakelists():
"""
helper for getting the default version from the project() command in the
root CMakeLists.txt file
"""
cmakelists_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), "..", "CMakeLists.txt")
)
with open(cmakelists_path, "r") as cmakelists_file:
for line in cmakelists_file.readlines():
line = line.strip()
if line.startswith("project("):
return Version(re.findall(r"\d+\.\d+", line)[0])
raise Exception(f"unable to read project version from {cmakelists_path}")
def main():
# phase 0: parse cmdline arguments
configParser = util.configRead("config.ini")
parser = argparse.ArgumentParser()
for section in configParser.sections():
add_argument(parser, section, "generation of C/C++ '%s' files." % section, True)
add_argument(parser, "clean", "cleaning previous generated files.")
add_argument(
parser, "build", "running cmake to generate and build projects.", False
)
add_argument(parser, "debug", "dump intermediate data to disk.")
add_argument(parser, "html", "generation of HTML files.", True)
add_argument(parser, "pdf", "generation of PDF file.")
add_argument(parser, "rst", "generation of reStructuredText files.", True)
parser.add_argument(
"--update_spec", type=str, help="root of integrated spec directory to update"
)
parser.add_argument(
"--ver",
type=parse_specs.Version,
default=get_version_from_cmakelists(),
required=False,
help="specification version to generate.",
)
parser.add_argument(
"--api-json",
type=str,
default="unified_runtime.json",
required=False,
help="json output file for the spec",
)
parser.add_argument(
"--clang-format",
type=str,
default="clang-format",
required=False,
help="path to clang-format executable",
)
parser.add_argument(
"--fast-mode",
action="store_true",
help="Disable sections which are slow to render",
)
args = vars(parser.parse_args())
args["rev"] = revision()
print("Version", args["ver"])
start = time.time()
# phase 1: extract configuration info from ini file
input = {"configs": [], "specs": [], "meta": {}, "ref": {}}
for section in configParser.sections():
input["configs"].append(
{
"name": section,
"namespace": configParser.get(section, "namespace"),
"tags": {
"$" + key: configParser.get(section, key)
for key in configParser.get(section, "tags").split(",")
},
}
)
# phase 2: parse specs
for config in input["configs"]:
specs, input["meta"], input["ref"] = parse_specs.parse(
config["name"], args["ver"], config["tags"], input["meta"], input["ref"]
)
input["specs"].append(specs)
util.jsonWrite(args["api_json"], input)
# phase 3: generate files
if args["clean"]:
clean()
incpath = os.path.join("../include/unified-runtime/")
srcpath = os.path.join("../source/")
docpath = os.path.join("../docs/")
generate_docs.prepare(docpath, args["rst"], args["html"], args["ver"])
for idx, specs in enumerate(input["specs"]):
config = input["configs"][idx]
if args[config["name"]]:
generate_code.generate_api(
incpath,
srcpath,
config["namespace"],
config["tags"],
args["ver"],
args["rev"],
specs,
input["meta"],
)
if args["rst"]:
generate_docs.generate_rst(
docpath,
config["name"],
config["namespace"],
config["tags"],
args["ver"],
args["rev"],
specs,
input["meta"],
args["fast_mode"],
)
if util.makeErrorCount():
print(
"\n%s Errors found during generation, stopping execution!"
% util.makeErrorCount()
)
return
if args["debug"]:
util.makoFileListWrite("generated.json")
# phase 4: build code
if args["build"]:
if not build():
print("\nBuild failed, stopping execution!")
return
util.formatGeneratedFiles(args["clang_format"])
# phase 5: prep for publication of html or pdf
if args["html"] or args["pdf"]:
generate_docs.generate_common(
docpath, configParser.sections(), args["ver"], args["rev"]
)
# phase 5: publish documentation
if args["html"]:
generate_docs.generate_html(docpath)
if args["pdf"]:
generate_docs.generate_pdf(docpath)
if args["update_spec"]:
update_spec(args["update_spec"])
print("\nCompleted in %.1f seconds!" % (time.time() - start))
if __name__ == "__main__":
main()