1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# Copyright (c) 2023 Huawei Device Co., Ltd.
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 tempfile
17import re
18import subprocess
19import io
20import argparse
21import os
22import sys
23import stat
24
25
26sys.path.append(
27    os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
28from scripts.util import build_utils
29
30
31def host_triple(rustc_path):
32    known_vars = dict()
33    args = [rustc_path, "-vV"]
34    proc = subprocess.Popen(args, stdout=subprocess.PIPE)
35    for lines in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
36        rustc_version = re.compile(r"(\w+): (.*)")
37        match = rustc_version.match(lines.rstrip())
38        if match:
39            known_vars[match.group(1)] = match.group(2)
40    proc.wait()
41    return known_vars.get("host")
42
43
44def run_build_script(args, env, tempdir):
45    process = subprocess.run([os.path.abspath(args.build_script)],
46                             env=env,
47                             cwd=args.src_dir,
48                             encoding='utf8',
49                             capture_output=True)
50
51    if process.stderr.rstrip():
52        print(process.stderr.rstrip(), file=sys.stderr)
53    process.check_returncode()
54
55    flags = ""
56    for line in process.stdout.split("\n"):
57        rustc_cfg = re.compile("cargo:rustc-cfg=(.*)")
58        match = rustc_cfg.match(line.rstrip())
59        if match:
60            flags = "%s--cfg\n%s\n" % (flags, match.group(1))
61
62    with build_utils.atomic_output(args.output) as output:
63        output.write(flags.encode("utf-8"))
64
65    if args.generated_files:
66        for generated_file in args.generated_files:
67            input_path = os.path.join(tempdir, generated_file)
68            output_path = os.path.join(args.out_dir, generated_file)
69            out_dir = os.path.dirname(output_path)
70            if not os.path.exists(out_dir):
71                os.makedirs(out_dir, exist_ok=True)
72            with os.fdopen(os.open(input_path,
73                                   os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR),
74                           'rb') as inputs:
75                with build_utils.atomic_output(output_path) as output:
76                    content = inputs.read()
77                    output.write(content)
78
79
80def set_env(args, rustc_path, tempdir):
81    rustc_abs_path = os.path.abspath(rustc_path)
82    src_dir_abs_path = os.path.abspath(args.src_dir)
83
84    env = {
85        "RUSTC": rustc_abs_path,
86        "HOST": host_triple(rustc_abs_path),
87        "CARGO_MANIFEST_DIR": src_dir_abs_path,
88        "OUT_DIR": tempdir,
89    }
90    if args.target:
91        env["TARGET"] = args.target
92    else:
93        env["TARGET"] = env.get("HOST")
94
95    env["CARGO_CFG_TARGET_ARCH"], *_ = env.get("TARGET").split("-")
96    if args.env:
97        env.update({key: val for key, val in (e.split('=') for e in args.env)})
98    if args.features:
99        for feature in args.features:
100            feature_name = feature.replace("-", "_").upper()
101            env[f"CARGO_FEATURE_{feature_name}"] = "1"
102
103    rust_log = os.environ.get("RUST_LOG")
104    rust_bt = os.environ.get("RUST_BACKTRACE")
105
106    if rust_log:
107        env["RUST_LOG"] = rust_log
108    if rust_bt:
109        env["RUST_BACKTRACE"] = rust_bt
110
111    return env
112
113
114def main():
115    parser = argparse.ArgumentParser()
116    parser.add_argument('--build-script',
117                        required=True,
118                        help='build script needed to run')
119    parser.add_argument('--target', help='rust target triple')
120    parser.add_argument('--features', help='features', nargs='+')
121    parser.add_argument('--env', help='environment variable', nargs='+')
122    parser.add_argument('--output',
123                        required=True,
124                        help='where to write output rustc flags')
125    parser.add_argument('--rust-prefix', required=True,
126                        help='rust path prefix')
127    parser.add_argument('--generated-files', nargs='+',
128                        help='any generated file')
129    parser.add_argument('--out-dir', required=True, help='ohos target out dir')
130    parser.add_argument('--src-dir', required=True,
131                        help='ohos target source dir')
132
133    args = parser.parse_args()
134    rustc_path = os.path.join(args.rust_prefix, "rustc")
135    with tempfile.TemporaryDirectory() as tempdir:
136        env = set_env(args, rustc_path, tempdir)
137        run_build_script(args, env, tempdir)
138
139
140if __name__ == '__main__':
141    sys.exit(main())
142