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 
14 import("//build/templates/rust/rust_template.gni")
15 template("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