[M120 Migration] Implement ewk_view_is_video_playing api
[platform/framework/web/chromium-efl.git] / build / rust / cargo_crate.gni
1 # Copyright 2021 The Chromium Authors
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import("//build/rust/rust_executable.gni")
6 import("//build/rust/rust_macro.gni")
7 import("//build/rust/rust_static_library.gni")
8
9 # This template allows for building Cargo crates within gn.
10 #
11 # It is intended for use with pre-existing (third party) code and
12 # is none too efficient. (It will stall the build pipeline whilst
13 # it runs build scripts to work out what flags are needed). First
14 # party code should directly use first-class gn targets, such as
15 # //build/rust/rust_static_library.gni or similar.
16 #
17 # Because it's intended for third-party code, it automatically
18 # defaults to //build/config/compiler:no_chromium_code which
19 # suppresses some warnings. If you *do* use this for first party
20 # code, you should remove that config and add the equivalent
21 # //build/config/compiler:chromium_code config.
22 #
23 # Arguments:
24 #  sources
25 #  crate_root
26 #  deps
27 #  aliased_deps
28 #  features
29 #  build_native_rust_unit_tests
30 #  edition
31 #  crate_name
32 #    All just as in rust_static_library.gni
33 #  library_configs/executable_configs
34 #    All just as in rust_target.gni
35 #
36 #  epoch (optional)
37 #    The major version of the library, which is used to differentiate between
38 #    multiple versions of the same library name. This includes all leading 0s
39 #    and the first non-zero value in the crate's version. This should be left
40 #    as the default, which is "0", for first-party code unless there are
41 #    multiple versions of a crate present. For third-party code, the version
42 #    epoch (matching the directory it is found in) should be specified.
43 #
44 #    Examples:
45 #      1.0.2 => epoch = "1"
46 #      4.2.0 => epoch = "4"
47 #      0.2.7 => epoch = "0.2"
48 #      0.0.3 => epoch = "0.0.3"
49 #
50 #  dev_deps
51 #    Same meaning as test_deps in rust_static_library.gni, but called
52 #    dev_deps to match Cargo.toml better.
53 #
54 #  build_root (optional)
55 #    Filename of build.rs build script.
56 #
57 #  build_deps (optional)
58 #    Build script dependencies
59 #
60 #  build_sources (optional)
61 #    List of sources for build script. Must be specified if
62 #    build_root is specified.
63 #
64 #  build_script_outputs (optional)
65 #    List of .rs files generated by the build script, if any.
66 #    Fine to leave undefined even if you have a build script.
67 #    This doesn't directly correspond to any Cargo variable,
68 #    but unfortunately is necessary for gn to build its dependency
69 #    trees automatically.
70 #    Many build scripts just output --cfg directives, in which case
71 #    no source code is generated and this can remain empty.
72 #
73 #  build_script_inputs (optional)
74 #    If the build script reads any files generated by build_deps,
75 #    as opposed to merely linking against them, add a list of such
76 #    files here. Again, this doesn't correspond to a Cargo variable
77 #    but is necessary for gn.
78 #
79 #  crate_type "bin", "proc-macro" or "rlib" (optional)
80 #    Whether to build an executable. The default is "rlib".
81 #    At present others are not supported.
82 #
83 #  cargo_pkg_authors
84 #  cargo_pkg_version
85 #  cargo_pkg_name
86 #  cargo_pkg_description
87 #    Strings as found within 'version' and similar fields within Cargo.toml.
88 #    Converted to environment variables passed to rustc, in case the crate
89 #    uses clap `crate_version!` or `crate_authors!` macros (fairly common in
90 #    command line tool help)
91
92 template("cargo_crate") {
93   _orig_target_name = target_name
94
95   _crate_name = _orig_target_name
96   if (defined(invoker.crate_name)) {
97     _crate_name = invoker.crate_name
98   }
99
100   # Construct metadata from the crate epoch or an explicitly provided metadata
101   # field.
102   _rustc_metadata = ""
103   if (defined(invoker.rustc_metadata)) {
104     _rustc_metadata = invoker.rustc_metadata
105   } else if (defined(invoker.epoch)) {
106     _rustc_metadata = "${_crate_name}-${invoker.epoch}"
107   }
108
109   # Executables need to have unique names. Work out a prefix.
110   if (defined(invoker.build_root)) {
111     _epochlabel = "vunknown"
112     if (defined(invoker.epoch)) {
113       _tempepoch = string_replace(invoker.epoch, ".", "_")
114       _epochlabel = "v${_tempepoch}"
115     }
116
117     # This name includes the target name to ensure it's unique for each possible
118     # build target in the same BUILD.gn file.
119     _build_script_name =
120         "${_crate_name}_${target_name}_${_epochlabel}_build_script"
121
122     # Where the OUT_DIR will point when running the build script exe, and
123     # compiling the crate library/binaries. This directory must include the
124     # target name to avoid collisions between multiple GN targets that exist
125     # in the same BUILD.gn.
126     _build_script_env_out_dir = "$target_gen_dir/$target_name"
127   }
128
129   _rustenv = []
130   if (defined(invoker.rustenv)) {
131     _rustenv = invoker.rustenv
132   }
133   if (defined(invoker.cargo_pkg_authors)) {
134     _rustenv += [ "CARGO_PKG_AUTHORS=${invoker.cargo_pkg_authors}" ]
135   }
136   if (defined(invoker.cargo_pkg_version)) {
137     _rustenv += [ "CARGO_PKG_VERSION=${invoker.cargo_pkg_version}" ]
138   }
139   if (defined(invoker.cargo_pkg_name)) {
140     _rustenv += [ "CARGO_PKG_NAME=${invoker.cargo_pkg_name}" ]
141   }
142   if (defined(invoker.cargo_pkg_description)) {
143     _rustenv += [ "CARGO_PKG_DESCRIPTION=${invoker.cargo_pkg_description}" ]
144   }
145
146   # Try to determine the CARGO_MANIFEST_DIR, preferring the directory
147   # with build.rs and otherwise assuming that the target contains a
148   # `crate/` subdirectory.
149   if (defined(invoker.build_root)) {
150     manifest_dir = rebase_path(get_path_info(invoker.build_root, "dir"), "")
151   } else {
152     build_gn_dir = get_label_info(target_name, "dir")
153     manifest_dir = rebase_path(build_gn_dir + "/crate", "")
154   }
155   _rustenv += [ "CARGO_MANIFEST_DIR=${manifest_dir}" ]
156
157   # cargo_crate() should set library_configs, executable_configs,
158   # proc_macro_configs. Not configs.
159   assert(!defined(invoker.configs))
160
161   # Work out what we're building.
162   _crate_type = "rlib"
163   if (defined(invoker.crate_type)) {
164     _crate_type = invoker.crate_type
165   }
166   if (_crate_type == "cdylib") {
167     # Crates are rarely cdylibs. The example encountered so far aims
168     # to expose a C API to other code. In a Chromium context, we don't
169     # want to build that as a dylib for a couple of reasons:
170     # * rust_shared_library does not work on Mac. rustc does not know
171     #   how to export the __llvm_profile_raw_version symbol.
172     # * even if it did work, this might require us to distribute extra
173     #   binaries (.so/.dylib etc.)
174     # For the only case we've had so far, it makes more sense to build
175     # the code as a static library which we can then link into downstream
176     # binaries.
177     _crate_type = "rlib"
178   }
179   if (_crate_type == "bin") {
180     _target_type = "rust_executable"
181     assert(!defined(invoker.epoch))
182     if (defined(invoker.executable_configs)) {
183       _configs = invoker.executable_configs
184     }
185   } else if (_crate_type == "proc-macro") {
186     _target_type = "rust_macro"
187     if (defined(invoker.proc_macro_configs)) {
188       _configs = invoker.proc_macro_configs
189     }
190   } else {
191     assert(_crate_type == "rlib")
192     _target_type = "rust_static_library"
193     if (defined(invoker.library_configs)) {
194       _configs = invoker.library_configs
195     }
196   }
197
198   # The main target, either a Rust source set or an executable.
199   target(_target_type, target_name) {
200     forward_variables_from(invoker,
201                            "*",
202                            TESTONLY_AND_VISIBILITY + [
203                                  "build_root",
204                                  "build_deps",
205                                  "build_sources",
206                                  "build_script_inputs",
207                                  "build_script_outputs",
208                                  "epoch",
209                                  "unit_test_target",
210                                  "configs",
211                                  "executable_configs",
212                                  "library_configs",
213                                  "proc_macro_configs",
214                                  "rustenv",
215                                  "dev_deps",
216                                ])
217     forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
218     if (defined(crate_type) && crate_type == "cdylib") {
219       # See comments above about cdylib.
220       crate_type = "rlib"
221     }
222
223     rustc_metadata = _rustc_metadata
224
225     # TODO(crbug.com/1422745): don't default to true. This requires changes to
226     # third_party.toml and gnrt when generating third-party build targets.
227     allow_unsafe = true
228
229     configs = []
230     if (defined(_configs)) {
231       configs += _configs
232     }
233
234     if (_crate_type == "rlib") {
235       # Forward configs for unit tests.
236       if (defined(invoker.executable_configs)) {
237         executable_configs = invoker.executable_configs
238       }
239     }
240
241     if (!defined(rustflags)) {
242       rustflags = []
243     }
244     rustenv = _rustenv
245
246     if (!defined(build_native_rust_unit_tests)) {
247       build_native_rust_unit_tests = _crate_type != "proc-macro"
248     }
249     if (build_native_rust_unit_tests) {
250       # Unit tests in a proc-macro crate type don't make sense, you can't
251       # compile executables against the `proc_macro` crate.
252       assert(_crate_type != "proc-macro")
253     }
254
255     # The unit tests for each target, if generated, should be unique as well.
256     # a) It needs to be unique even if multiple build targets have the same
257     #    `crate_name`, but different target names.
258     # b) It needs to be unique even if multiple build targets have the same
259     #    `crate_name` and target name, but different epochs.
260     _unit_test_unique_target_name = ""
261     if (_crate_name != _orig_target_name) {
262       _unit_test_unique_target_name = "${_orig_target_name}_"
263     }
264     _unit_test_unique_epoch = ""
265     if (defined(invoker.epoch)) {
266       _epoch_str = string_replace(invoker.epoch, ".", "_")
267       _unit_test_unique_epoch = "v${_epoch_str}_"
268     }
269     if (defined(output_dir) && output_dir != "") {
270       unit_test_output_dir = output_dir
271     }
272     unit_test_target = "${_unit_test_unique_target_name}${_crate_name}_${_unit_test_unique_epoch}unittests"
273
274     if ((!defined(output_dir) || output_dir == "") && _crate_type == "rlib") {
275       # Cargo crate rlibs can be compiled differently for tests, and must not
276       # collide with the production outputs. This does *not* override the
277       # unit_test_output_dir, which is set above, as that target is not an rlib.
278       output_dir = "$target_out_dir/$_orig_target_name"
279     }
280
281     if (defined(invoker.dev_deps)) {
282       test_deps = invoker.dev_deps
283     }
284
285     if (defined(invoker.build_root)) {
286       # Uh-oh, we have a build script
287       if (!defined(deps)) {
288         deps = []
289       }
290       if (!defined(sources)) {
291         sources = []
292       }
293       if (!defined(inputs)) {
294         inputs = []
295       }
296
297       # This... is a bit weird. We generate a file called cargo_flags.rs which
298       # does not actually contain Rust code, but instead some flags to add
299       # to the rustc command line. We need it to end in a .rs extension so that
300       # we can include it in the 'sources' line and thus have dependency
301       # calculation done correctly. data_deps won't work because targets don't
302       # require them to be present until runtime.
303       flags_file = "$_build_script_env_out_dir/cargo_flags.rs"
304       rustflags += [ "@" + rebase_path(flags_file, root_build_dir) ]
305       sources += [ flags_file ]
306       if (defined(invoker.build_script_outputs)) {
307         # Build scripts may output arbitrary files. They are usually included in
308         # the main Rust target using include! or include_str! and therefore the
309         # filename may be .rs or may be arbitrary. We want to educate ninja
310         # about the dependency either way.
311         foreach(extra_source,
312                 filter_include(invoker.build_script_outputs, [ "*.rs" ])) {
313           sources += [ "$_build_script_env_out_dir/$extra_source" ]
314         }
315         foreach(extra_source,
316                 filter_exclude(invoker.build_script_outputs, [ "*.rs" ])) {
317           inputs += [ "$_build_script_env_out_dir/$extra_source" ]
318         }
319       }
320       deps += [ ":${_build_script_name}_output" ]
321     }
322   }
323
324   if (defined(invoker.build_root)) {
325     # Extra targets required to make build script work
326     action("${_build_script_name}_output") {
327       script = rebase_path("//build/rust/run_build_script.py")
328       build_script_target = ":${_build_script_name}($rust_macro_toolchain)"
329       deps = [ build_script_target ]
330
331       # The build script may be built with a different toolchain when
332       # cross-compiling (the host toolchain) so we must find the path relative
333       # to that.
334       _build_script_root_out_dir =
335           get_label_info(build_script_target, "root_out_dir")
336       _build_script_exe = "$_build_script_root_out_dir/$_build_script_name"
337
338       # The executable is always built with the `rust_macro_toolchain` which
339       # targets the `host_os`. The rule here is on the `target_toolchain` which
340       # can be different (e.g. compiling on Linux, targeting Windows).
341       if (host_os == "win") {
342         _build_script_exe = "${_build_script_exe}.exe"
343       }
344
345       _flags_file = "$_build_script_env_out_dir/cargo_flags.rs"
346
347       inputs = [ _build_script_exe ]
348       outputs = [ _flags_file ]
349       args = [
350         "--build-script",
351         rebase_path(_build_script_exe, root_build_dir),
352         "--output",
353         rebase_path(_flags_file, root_build_dir),
354         "--rust-prefix",
355         rebase_path("${rust_sysroot}/bin", root_build_dir),
356         "--out-dir",
357         rebase_path(_build_script_env_out_dir, root_build_dir),
358         "--src-dir",
359         rebase_path(get_path_info(invoker.build_root, "dir"), root_build_dir),
360       ]
361       if (defined(rust_abi_target) && rust_abi_target != "") {
362         args += [
363           "--target",
364           rust_abi_target,
365         ]
366       }
367       if (defined(invoker.features)) {
368         args += [ "--features" ]
369         args += invoker.features
370       }
371       if (defined(invoker.build_script_outputs)) {
372         args += [ "--generated-files" ]
373         args += invoker.build_script_outputs
374         foreach(generated_file, invoker.build_script_outputs) {
375           outputs += [ "$_build_script_env_out_dir/$generated_file" ]
376         }
377       }
378       if (_rustenv != []) {
379         args += [ "--env" ]
380         args += _rustenv
381       }
382       if (defined(invoker.build_script_inputs)) {
383         inputs += invoker.build_script_inputs
384       }
385     }
386
387     if (toolchain_for_rust_host_build_tools) {
388       # The build script is only available to be built on the host, and we use
389       # the rust_macro_toolchain for it to unblock building them while the
390       # Chromium stdlib is still being compiled.
391       rust_executable(_build_script_name) {
392         sources = invoker.build_sources
393         crate_root = invoker.build_root
394         if (defined(invoker.build_deps)) {
395           deps = invoker.build_deps
396         }
397         if (defined(invoker.build_script_inputs)) {
398           inputs = invoker.build_script_inputs
399         }
400
401         # The ${_build_script_name}_output target looks for the exe in this
402         # location. Due to how the Windows component build works, this has to
403         # be $root_out_dir for all EXEs. In component build, C++ links to the
404         # CRT as a DLL, and if Rust does not match, we can't link mixed target
405         # Rust EXE/DLLs, as the headers in C++ said something different than
406         # what Rust links. Since the CRT DLL is placed in the $root_out_dir,
407         # an EXE can find it if it's also placed in that dir.
408         output_dir = root_out_dir
409         rustenv = _rustenv
410         forward_variables_from(invoker,
411                                [
412                                  "features",
413                                  "edition",
414                                  "rustflags",
415                                ])
416         configs -= [
417           "//build/config/compiler:chromium_code",
418
419           # Avoid generating profiling data for build scripts.
420           #
421           # TODO(crbug.com/1426472): determine for sure whether to remove this
422           # config. I'm not sure of the overlap between PGO instrumentation and
423           # code coverage instrumentation, but we definitely don't want build
424           # script coverage for PGO, while we might for test coverage metrics.
425           #
426           # If we do include build script output in test metrics, it could be
427           # misleading: exercising some code from a build script doesn't give us
428           # the same signal as an actual test.
429           "//build/config/coverage:default_coverage",
430         ]
431         configs += [ "//build/config/compiler:no_chromium_code" ]
432       }
433     } else {
434       not_needed(invoker,
435                  [
436                    "build_sources",
437                    "build_deps",
438                    "build_root",
439                    "build_script_inputs",
440                    "build_script_outputs",
441                  ])
442     }
443   } else {
444     not_needed([
445                  "_name_specific_output_dir",
446                  "_orig_target_name",
447                ])
448   }
449 }
450
451 set_defaults("cargo_crate") {
452   library_configs = default_compiler_configs
453   executable_configs = default_executable_configs
454   proc_macro_configs = default_rust_proc_macro_configs
455 }