1# Copyright (c) 2023 Huawei Device Co., Ltd.
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at
5#
6#     http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
14import("//build/templates/rust/rust_template.gni")
15template("ohos_cargo_crate") {
16  orig_target_name = target_name
17
18  _crate_name = orig_target_name
19  if (defined(invoker.crate_name)) {
20    _crate_name = invoker.crate_name
21  }
22  assert(_crate_name != "")
23
24  _rustenv = []
25  if (defined(invoker.rustenv)) {
26    _rustenv = invoker.rustenv
27  }
28  if (defined(invoker.cargo_pkg_authors)) {
29    _rustenv += [ string_join("",
30                              [
31                                "CARGO_PKG_AUTHORS=",
32                                invoker.cargo_pkg_authors,
33                              ]) ]
34  }
35  if (defined(invoker.cargo_pkg_version)) {
36    _rustenv += [ string_join("",
37                              [
38                                "CARGO_PKG_VERSION=",
39                                invoker.cargo_pkg_version,
40                              ]) ]
41  }
42  if (defined(invoker.cargo_pkg_name)) {
43    _rustenv += [ string_join("",
44                              [
45                                "CARGO_PKG_NAME=",
46                                invoker.cargo_pkg_name,
47                              ]) ]
48  }
49  if (defined(invoker.cargo_pkg_description)) {
50    _rustenv += [ string_join("",
51                              [
52                                "CARGO_PKG_DESCRIPTION=",
53                                invoker.cargo_pkg_description,
54                              ]) ]
55  }
56
57  if (defined(invoker.build_root)) {
58    _epochlabel = "unknown"
59    if (defined(invoker.epoch)) {
60      _tempepoch = string_replace(invoker.epoch, ".", "_")
61      _epochlabel = "${_tempepoch}"
62    }
63    build_script_name =
64        "${_crate_name}_${target_name}_${_epochlabel}_build_script"
65  }
66  _rustflags = []
67  rust_target(target_name) {
68    forward_variables_from(invoker,
69                           "*",
70                           [
71                             "testonly",
72                             "visibility",
73                             "build_root",
74                             "build_sources",
75                             "build_deps",
76                             "build_script_inputs",
77                             "build_script_outputs",
78                             "output_dir",
79                             "target_type",
80                             "configs",
81                             "rustenv",
82                           ])
83
84    rustenv = _rustenv
85    if (defined(invoker.rustc_lints)) {
86      rustc_lints = invoker.rustc_lints
87    }
88    if (defined(invoker.clippy_lints)) {
89      clippy_lints = invoker.clippy_lints
90    }
91
92    if (!defined(rustc_lints) && !defined(clippy_lints)) {
93      file_path =
94          get_path_info(get_path_info(invoker.sources, "dir"), "abspath")
95      file_path_split = string_split(file_path[0], "/")
96      source_dir_begin = file_path_split[2]
97
98      if (source_dir_begin == "third_party") {
99        _rustflags += allowAllLints
100      } else if (source_dir_begin == "prebuilts") {
101        _rustflags += allowAllLints
102      } else if (source_dir_begin == "vendor" &&
103                 file_path_split[3] == "open_source") {
104        _rustflags += allowAllLints
105      } else if (source_dir_begin == "vendor") {
106        _rustflags += rustcVendorLints
107        _rustflags += clippyVendorLints
108      } else if (source_dir_begin == "device") {
109        _rustflags += rustcVendorLints
110        _rustflags += clippyVendorLints
111      } else {
112        _rustflags += rustcOhosLints
113        _rustflags += clippyOhosLints
114      }
115    }
116
117    if (defined(rustc_lints)) {
118      if (invoker.rustc_lints == "openharmony") {
119        _rustflags += rustcOhosLints
120      } else if (rustc_lints == "vendor") {
121        _rustflags += rustcVendorLints
122      } else if (rustc_lints == "none") {
123        _rustflags += allowAllLints
124      }
125    }
126    if (defined(clippy_lints)) {
127      if (invoker.clippy_lints == "openharmony") {
128        _rustflags += clippyOhosLints
129      } else if (clippy_lints == "vendor") {
130        _rustflags += clippyVendorLints
131      } else if (clippy_lints == "none") {
132        _rustflags += allowAllLints
133      }
134    }
135    if (!defined(rustflags)) {
136      rustflags = _rustflags
137    } else {
138      rustflags += _rustflags
139    }
140
141    crate_type = "rlib"
142    if (defined(invoker.crate_type)) {
143      crate_type = invoker.crate_type
144    }
145    if (crate_type == "bin") {
146      target_type = "ohos_executable"
147      assert(!defined(invoker.epoch))
148    } else if (crate_type == "proc-macro") {
149      target_type = "rust_proc_macro"
150    } else {
151      assert(crate_type == "rlib" || crate_type == "dylib")
152      target_type = "ohos_rust_library"
153    }
154
155    output_dir = "${target_out_dir}/${orig_target_name}"
156
157    if (defined(invoker.build_root)) {
158      if (!defined(deps)) {
159        deps = []
160      }
161      if (!defined(sources)) {
162        sources = []
163      }
164
165      _build_script_target_out_dir =
166          get_label_info(":${build_script_name}_output", "target_out_dir")
167      _build_script_out_dir = "$_build_script_target_out_dir/$orig_target_name"
168
169      flags_file = "$_build_script_out_dir/cargo_flags.rs"
170      rustflags += [ "@" + rebase_path(flags_file, root_build_dir) ]
171      sources += [ flags_file ]
172      if (defined(invoker.build_script_outputs)) {
173        inputs = []
174        foreach(extra_source,
175                filter_exclude(invoker.build_script_outputs, [ "*.rs" ])) {
176          inputs += [ "$_build_script_out_dir/$extra_source" ]
177        }
178
179        foreach(extra_source,
180                filter_include(invoker.build_script_outputs, [ "*.rs" ])) {
181          sources += [ "$_build_script_out_dir/$extra_source" ]
182        }
183      }
184      deps += [ ":${build_script_name}_output" ]
185    } else {
186      not_needed([ "orig_target_name" ])
187    }
188  }
189
190  if (defined(invoker.build_root)) {
191    action("${build_script_name}_output") {
192      script = rebase_path("//build/templates/rust/run_build_script.py")
193      build_script_target = ":${build_script_name}($host_toolchain)"
194      deps = [ build_script_target ]
195
196      if (defined(invoker.subsystem_name) && defined(invoker.part_name)) {
197        subsystem_name = invoker.subsystem_name
198        part_name = invoker.part_name
199      } else if (defined(invoker.part_name)) {
200        part_name = invoker.part_name
201        _part_subsystem_info_file =
202            "$root_build_dir/build_configs/parts_info/part_subsystem.json"
203        _arguments = [
204          "--part-name",
205          part_name,
206          "--part-subsystem-info-file",
207          rebase_path(_part_subsystem_info_file, root_build_dir),
208        ]
209        get_subsystem_script = "//build/templates/common/get_subsystem_name.py"
210        subsystem_name =
211            exec_script(get_subsystem_script, _arguments, "trim string")
212      } else if (defined(invoker.subsystem_name)) {
213        subsystem_name = invoker.subsystem_name
214        part_name = subsystem_name
215      } else {
216        subsystem_name = "build"
217        part_name = "build_framework"
218      }
219      assert(subsystem_name != "")
220      assert(part_name != "")
221
222      if (current_toolchain == host_toolchain) {
223        _build_script_build_dir = "${root_out_dir}"
224      } else if (is_mingw) {
225        _build_script_build_dir = "${root_out_dir}/../clang_x64"
226      } else {
227        _build_script_build_dir = "${root_out_dir}/clang_x64"
228      }
229
230      if (is_standard_system) {
231        _build_script_exe_dir =
232            "${_build_script_build_dir}/${subsystem_name}/${part_name}"
233      } else {
234        _build_script_exe_dir = "${_build_script_build_dir}"
235      }
236      build_script = "$_build_script_exe_dir/${build_script_name}"
237
238      if (is_win) {
239        build_script = "$_build_script_exe_dir/${build_script_name}.exe"
240      }
241
242      _build_script_out_dir = "$target_out_dir/$orig_target_name"
243      flags_file = "$_build_script_out_dir/cargo_flags.rs"
244
245      args = [
246        "--build-script",
247        rebase_path(build_script, root_build_dir),
248        "--rust-prefix",
249        rebase_path(
250            "//prebuilts/rustc/${host_platform_dir}/${rust_version}/bin",
251            root_build_dir),
252        "--output",
253        rebase_path(flags_file, root_build_dir),
254        "--src-dir",
255        rebase_path(get_path_info(invoker.build_root, "dir"), root_build_dir),
256        "--out-dir",
257        rebase_path(_build_script_out_dir, root_build_dir),
258      ]
259      if (defined(rust_abi_target) && rust_abi_target != "") {
260        args += [
261          "--target",
262          rust_abi_target,
263        ]
264      }
265
266      if (_rustenv != []) {
267        args += [ "--env" ]
268        args += _rustenv
269      }
270
271      if (defined(invoker.features)) {
272        args += [ "--features" ]
273        args += invoker.features
274      }
275      outputs = [ flags_file ]
276      inputs = [ build_script ]
277      if (defined(invoker.build_script_outputs)) {
278        foreach(generated_file, invoker.build_script_outputs) {
279          outputs += [ "$_build_script_out_dir/$generated_file" ]
280        }
281        args += [ "--generated-files" ]
282        args += invoker.build_script_outputs
283      }
284
285      if (defined(invoker.build_script_inputs)) {
286        inputs += invoker.build_script_inputs
287      }
288    }
289
290    rust_target(build_script_name) {
291      target_type = "ohos_executable"
292      sources = invoker.build_sources
293      crate_root = invoker.build_root
294      if (defined(invoker.build_deps)) {
295        deps = invoker.build_deps
296      }
297      rustenv = _rustenv
298      forward_variables_from(invoker,
299                             [
300                               "features",
301                               "edition",
302                               "rustflags",
303                               "subsystem_name",
304                               "part_name",
305                             ])
306    }
307  }
308}
309