Move gen-kotlin-build-file.sh to python

Kotlin common multiplatform sources support will require more
complexity in gen-kotlin-build-file.sh, move it to python instead.

Test: m checkbuild
Change-Id: I02312160ad781877f1fec971168331c0dcecf136
This commit is contained in:
Colin Cross 2020-06-25 17:12:28 -07:00
parent 8ba7d47bba
commit 9b1aa0cb86
7 changed files with 201 additions and 147 deletions

View file

@ -110,7 +110,7 @@ func init() {
pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
pctx.SourcePathVariable("GenKotlinBuildFileCmd", "build/soong/scripts/gen-kotlin-build-file.sh")
pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file.py")
pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
pctx.SourcePathVariable("PackageCheckCmd", "build/soong/scripts/package-check.sh")

View file

@ -31,7 +31,9 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports
Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
`mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
`${config.GenKotlinBuildFileCmd} $classpath "$name" $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
`${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
` --out "$kotlinBuildFile" && ` +
`${config.KotlincCmd} ${config.JavacHeapFlags} $kotlincFlags ` +
`-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile -kotlin-home $emptyDir && ` +
`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` +
@ -74,7 +76,7 @@ func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath,
Inputs: srcFiles,
Implicits: deps,
Args: map[string]string{
"classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"),
"classpath": flags.kotlincClasspath.FormJavaClassPath(""),
"kotlincFlags": flags.kotlincFlags,
"srcJars": strings.Join(srcJars.Strings(), " "),
"classesDir": android.PathForModuleOut(ctx, "kotlinc", "classes").String(),
@ -93,7 +95,9 @@ var kapt = pctx.AndroidRemoteStaticRule("kapt", android.RemoteRuleSupports{Goma:
Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` +
`mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
`${config.GenKotlinBuildFileCmd} $classpath "$name" "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
`${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
` --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
` --out "$kotlinBuildFile" && ` +
`${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` +
`-Xplugin=${config.KotlinKaptJar} ` +
`-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` +
@ -162,7 +166,7 @@ func kotlinKapt(ctx android.ModuleContext, srcJarOutputFile, resJarOutputFile an
Inputs: srcFiles,
Implicits: deps,
Args: map[string]string{
"classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"),
"classpath": flags.kotlincClasspath.FormJavaClassPath(""),
"kotlincFlags": flags.kotlincFlags,
"srcJars": strings.Join(srcJars.Strings(), " "),
"srcJarDir": android.PathForModuleOut(ctx, "kapt", "srcJars").String(),

View file

@ -152,5 +152,17 @@ python_test_host {
python_binary_host {
name: "lint-project-xml",
main: "lint-project-xml.py",
srcs: ["lint-project-xml.py"],
srcs: [
"lint-project-xml.py",
"ninja_rsp.py",
],
}
python_binary_host {
name: "gen-kotlin-build-file.py",
main: "gen-kotlin-build-file.py",
srcs: [
"gen-kotlin-build-file.py",
"ninja_rsp.py",
],
}

View file

@ -0,0 +1,94 @@
#!/usr/bin/env python3
#
# Copyright 2018 Google Inc. All rights reserved.
#
# 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.
# Generates kotlinc module xml file to drive kotlinc
import argparse
import os
from ninja_rsp import NinjaRspFileReader
def parse_args():
"""Parse commandline arguments."""
def convert_arg_line_to_args(arg_line):
for arg in arg_line.split():
if arg.startswith('#'):
return
if not arg.strip():
continue
yield arg
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
parser.convert_arg_line_to_args = convert_arg_line_to_args
parser.add_argument('--out', dest='out',
help='file to which the module.xml contents will be written.')
parser.add_argument('--classpath', dest='classpath', action='append', default=[],
help='classpath to pass to kotlinc.')
parser.add_argument('--name', dest='name',
help='name of the module.')
parser.add_argument('--out_dir', dest='out_dir',
help='directory to which kotlinc will write output files.')
parser.add_argument('--srcs', dest='srcs', action='append', default=[],
help='file containing whitespace separated list of source files.')
parser.add_argument('--common_srcs', dest='common_srcs', action='append', default=[],
help='file containing whitespace separated list of common multiplatform source files.')
return parser.parse_args()
def main():
"""Program entry point."""
args = parse_args()
if not args.out:
raise RuntimeError('--out argument is required')
if not args.name:
raise RuntimeError('--name argument is required')
with open(args.out, 'w') as f:
# Print preamble
f.write('<modules>\n')
f.write(' <module name="%s" type="java-production" outputDir="%s">\n' % (args.name, args.out_dir or ''))
# Print classpath entries
for c in args.classpath:
for entry in c.split(':'):
path = os.path.abspath(entry)
f.write(' <classpath path="%s"/>\n' % path)
# For each rsp file, print source entries
for rsp_file in args.srcs:
for src in NinjaRspFileReader(rsp_file):
path = os.path.abspath(src)
if src.endswith('.java'):
f.write(' <javaSourceRoots path="%s"/>\n' % path)
elif src.endswith('.kt'):
f.write(' <sources path="%s"/>\n' % path)
else:
raise RuntimeError('unknown source file type %s' % file)
for rsp_file in args.common_srcs:
for src in NinjaRspFileReader(rsp_file):
path = os.path.abspath(src)
f.write(' <sources path="%s"/>\n' % path)
f.write(' <commonSources path="%s"/>\n' % path)
f.write(' </module>\n')
f.write('</modules>\n')
if __name__ == '__main__':
main()

View file

@ -1,73 +0,0 @@
#!/bin/bash -e
# Copyright 2018 Google Inc. All rights reserved.
#
# 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.
# Generates kotlinc module xml file to standard output based on rsp files
if [[ -z "$1" ]]; then
echo "usage: $0 <classpath> <name> <outDir> <rspFiles>..." >&2
exit 1
fi
# Classpath variable has a tendency to be prefixed by "-classpath", remove it.
if [[ $1 == "-classpath" ]]; then
shift
fi;
classpath=$1
name=$2
out_dir=$3
shift 3
# Path in the build file may be relative to the build file, we need to make them
# absolute
prefix="$(pwd)"
get_abs_path () {
local file="$1"
if [[ "${file:0:1}" == '/' ]] ; then
echo "${file}"
else
echo "${prefix}/${file}"
fi
}
# Print preamble
echo "<modules><module name=\"${name}\" type=\"java-production\" outputDir=\"${out_dir}\">"
# Print classpath entries
for file in $(echo "$classpath" | tr ":" "\n"); do
path="$(get_abs_path "$file")"
echo " <classpath path=\"${path}\"/>"
done
# For each rsp file, print source entries
while (( "$#" )); do
for file in $(cat "$1"); do
path="$(get_abs_path "$file")"
if [[ $file == *.java ]]; then
echo " <javaSourceRoots path=\"${path}\"/>"
elif [[ $file == *.kt ]]; then
echo " <sources path=\"${path}\"/>"
else
echo "Unknown source file type ${file}"
exit 1
fi
done
shift
done
echo "</module></modules>"

View file

@ -19,6 +19,8 @@
import argparse
from ninja_rsp import NinjaRspFileReader
def check_action(check_type):
"""
@ -91,74 +93,6 @@ def parse_args():
return parser.parse_args()
class NinjaRspFileReader:
"""
Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
non-standard character by surrounding the whole entry with single quotes, and then replacing
any single quotes in the entry with the escape sequence '\''.
"""
def __init__(self, filename):
self.f = open(filename, 'r')
self.r = self.character_reader(self.f)
def __iter__(self):
return self
def character_reader(self, f):
"""Turns a file into a generator that returns one character at a time."""
while True:
c = f.read(1)
if c:
yield c
else:
return
def __next__(self):
entry = self.read_entry()
if entry:
return entry
else:
raise StopIteration
def read_entry(self):
c = next(self.r, "")
if not c:
return ""
elif c == "'":
return self.read_quoted_entry()
else:
entry = c
for c in self.r:
if c == " " or c == "\n":
break
entry += c
return entry
def read_quoted_entry(self):
entry = ""
for c in self.r:
if c == "'":
# Either the end of the quoted entry, or the beginning of an escape sequence, read the next
# character to find out.
c = next(self.r)
if not c or c == " " or c == "\n":
# End of the item
return entry
elif c == "\\":
# Escape sequence, expect a '
c = next(self.r)
if c != "'":
# Malformed escape sequence
raise "malformed escape sequence %s'\\%s" % (entry, c)
entry += "'"
else:
raise "malformed escape sequence %s'%s" % (entry, c)
else:
entry += c
raise "unterminated quoted entry %s" % entry
def write_project_xml(f, args):
test_attr = "test='true' " if args.test else ""

83
scripts/ninja_rsp.py Normal file
View file

@ -0,0 +1,83 @@
# Copyright (C) 2020 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.
#
"""This file reads entries from a Ninja rsp file."""
class NinjaRspFileReader:
"""
Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
non-standard character by surrounding the whole entry with single quotes, and then replacing
any single quotes in the entry with the escape sequence '\''.
"""
def __init__(self, filename):
self.f = open(filename, 'r')
self.r = self.character_reader(self.f)
def __iter__(self):
return self
def character_reader(self, f):
"""Turns a file into a generator that returns one character at a time."""
while True:
c = f.read(1)
if c:
yield c
else:
return
def __next__(self):
entry = self.read_entry()
if entry:
return entry
else:
raise StopIteration
def read_entry(self):
c = next(self.r, "")
if not c:
return ""
elif c == "'":
return self.read_quoted_entry()
else:
entry = c
for c in self.r:
if c == " " or c == "\n":
break
entry += c
return entry
def read_quoted_entry(self):
entry = ""
for c in self.r:
if c == "'":
# Either the end of the quoted entry, or the beginning of an escape sequence, read the next
# character to find out.
c = next(self.r)
if not c or c == " " or c == "\n":
# End of the item
return entry
elif c == "\\":
# Escape sequence, expect a '
c = next(self.r)
if c != "'":
# Malformed escape sequence
raise "malformed escape sequence %s'\\%s" % (entry, c)
entry += "'"
else:
raise "malformed escape sequence %s'%s" % (entry, c)
else:
entry += c
raise "unterminated quoted entry %s" % entry