1e41f4b71Sopenharmony_ci# Build System Coding Specifications and Best Practices
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Overview
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciGenerate Ninja (GN) is a meta-build system that generates build files for Ninja. It is the front end of Ninja. GN and Ninja together complete OpenHarmony build tasks.
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ci### GN
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciGN is used in large software systems such as Chromium, Fuchsia, and OpenHarmony. However, the GN syntax has limitations rooted in its design philosophy. For details, see https://gn.googlesource.com/gn/+/main/docs/language.md#Design-philosophy. For example, GN does not support wildcards and cannot get the length of a list. If you find it complex to implement something with GN, stop and consider whether it is necessary to do it. For more details about GN, see https://gn.googlesource.com/gn/+/main/docs/.
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci### Intended Audience and Purpose
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ciThis document is intended for OpenHarmony developers. It describes the GN coding style and practices, but does not cover the GN syntax. For details about the GN basics, see https://gn.googlesource.com/gn/+/main/docs/reference.md.
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci### General Principles
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ciScripts must be easy to read and maintain, and have good scalability and performance while functioning well.
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci## Coding Style
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci### Naming
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ciFollow the Linux kernel naming style, that is, lowercase letters + underscores (_).
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ci#### Local Variables
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ciA local variable is a variable restricted to use in a certain scope and cannot be passed down.
28e41f4b71Sopenharmony_ci
29e41f4b71Sopenharmony_ciDifferent from global variables, local variables start with an underscore (_).
30e41f4b71Sopenharmony_ci
31e41f4b71Sopenharmony_ci```shell
32e41f4b71Sopenharmony_ci# Example 1:
33e41f4b71Sopenharmony_ciaction("some_action") {
34e41f4b71Sopenharmony_ci  ...
35e41f4b71Sopenharmony_ci  # _output is a local variable.
36e41f4b71Sopenharmony_ci  _output = "${target_out_dir}/${target_name}.out"
37e41f4b71Sopenharmony_ci  outputs = [ _output ]
38e41f4b71Sopenharmony_ci  args = [
39e41f4b71Sopenharmony_ci    ...
40e41f4b71Sopenharmony_ci      "--output",
41e41f4b71Sopenharmony_ci      rebase_path(_output, root_build_dir),
42e41f4b71Sopenharmony_ci      ...
43e41f4b71Sopenharmony_ci  ]
44e41f4b71Sopenharmony_ci  ...
45e41f4b71Sopenharmony_ci}
46e41f4b71Sopenharmony_ci```
47e41f4b71Sopenharmony_ci
48e41f4b71Sopenharmony_ci#### Global Variables
49e41f4b71Sopenharmony_ci
50e41f4b71Sopenharmony_ciA global variable starts with a lowercase letter.
51e41f4b71Sopenharmony_ci
52e41f4b71Sopenharmony_ciUse **declare_args** to declare the variable value only if the variable value can be modified by **gn args**.
53e41f4b71Sopenharmony_ci
54e41f4b71Sopenharmony_ci```shell
55e41f4b71Sopenharmony_ci# Example 2
56e41f4b71Sopenharmony_cideclare_args() {
57e41f4b71Sopenharmony_ci  # The value of some_feature can be changed by gn args.
58e41f4b71Sopenharmony_ci  some_feature = false
59e41f4b71Sopenharmony_ci}
60e41f4b71Sopenharmony_ci```
61e41f4b71Sopenharmony_ci
62e41f4b71Sopenharmony_ci#### Targets
63e41f4b71Sopenharmony_ci
64e41f4b71Sopenharmony_ciName the targets in the lowercase letters + underscores (_) format.
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ciName the subtargets in templates in the ${target_name}+double underscores (__)+suffix format. This naming convention has the following advantages:
67e41f4b71Sopenharmony_ci
68e41f4b71Sopenharmony_ci- ${target_name} prevents duplicate subtarget names.
69e41f4b71Sopenharmony_ci
70e41f4b71Sopenharmony_ci- The double underscores (__) help locate the module to which a subtarget belongs.
71e41f4b71Sopenharmony_ci  
72e41f4b71Sopenharmony_ci  ```shell
73e41f4b71Sopenharmony_ci  # Example 3
74e41f4b71Sopenharmony_ci  template("ohos_shared_library") {
75e41f4b71Sopenharmony_ci    # "{target_name}" (Target name) + "__" (double underscores) + "notice" (suffix)
76e41f4b71Sopenharmony_ci    _notice_target = "${target_name}__notice"
77e41f4b71Sopenharmony_ci    collect_notice(_notice_target) {
78e41f4b71Sopenharmony_ci      ...
79e41f4b71Sopenharmony_ci    }
80e41f4b71Sopenharmony_ci    shared_library(target_name) {
81e41f4b71Sopenharmony_ci      ...
82e41f4b71Sopenharmony_ci    }
83e41f4b71Sopenharmony_ci  }
84e41f4b71Sopenharmony_ci  ```
85e41f4b71Sopenharmony_ci
86e41f4b71Sopenharmony_ci#### Custom Templates
87e41f4b71Sopenharmony_ci
88e41f4b71Sopenharmony_ciName templates in the verb+object format.
89e41f4b71Sopenharmony_ci
90e41f4b71Sopenharmony_ci```shell
91e41f4b71Sopenharmony_ci# Example 4
92e41f4b71Sopenharmony_ci# Good
93e41f4b71Sopenharmony_citemplate("compile_resources") {
94e41f4b71Sopenharmony_ci  ...
95e41f4b71Sopenharmony_ci}
96e41f4b71Sopenharmony_ci```
97e41f4b71Sopenharmony_ci
98e41f4b71Sopenharmony_ci### Formatting
99e41f4b71Sopenharmony_ci
100e41f4b71Sopenharmony_ciGN scripts must be formatted before being submitted. Formatting ensures consistency in style, such as code alignment and line feed. Use the format tool provided by GN to format your scripts. The command is as follows: 
101e41f4b71Sopenharmony_ci
102e41f4b71Sopenharmony_ci```shell
103e41f4b71Sopenharmony_ci$ gn format path-to-BUILD.gn
104e41f4b71Sopenharmony_ci```
105e41f4b71Sopenharmony_ci
106e41f4b71Sopenharmony_ci**gn format** sorts the imported files in alphabetical order. To maintain the original sequence, add an empty comment line.
107e41f4b71Sopenharmony_ci
108e41f4b71Sopenharmony_ciFor example, the original import sequence is as follows:
109e41f4b71Sopenharmony_ci
110e41f4b71Sopenharmony_ci```shell
111e41f4b71Sopenharmony_ci# Example 5
112e41f4b71Sopenharmony_ciimport("//b.gni")
113e41f4b71Sopenharmony_ciimport("//a.gni")
114e41f4b71Sopenharmony_ci```
115e41f4b71Sopenharmony_ci
116e41f4b71Sopenharmony_ci**gn format** sorts the files as follows:
117e41f4b71Sopenharmony_ci
118e41f4b71Sopenharmony_ci```shell
119e41f4b71Sopenharmony_ciimport("//a.gni")
120e41f4b71Sopenharmony_ciimport("//b.gni")
121e41f4b71Sopenharmony_ci```
122e41f4b71Sopenharmony_ci
123e41f4b71Sopenharmony_ciTo maintain the original sequence, add an empty comment line.
124e41f4b71Sopenharmony_ci
125e41f4b71Sopenharmony_ci```shell
126e41f4b71Sopenharmony_ciimport("//b.gni")
127e41f4b71Sopenharmony_ci# Comment to keep the original sequence
128e41f4b71Sopenharmony_ciimport("//a.gni")
129e41f4b71Sopenharmony_ci```
130e41f4b71Sopenharmony_ci
131e41f4b71Sopenharmony_ci## Coding Practices
132e41f4b71Sopenharmony_ci
133e41f4b71Sopenharmony_ci### Guidelines
134e41f4b71Sopenharmony_ci
135e41f4b71Sopenharmony_ciThe build script completes the following tasks:
136e41f4b71Sopenharmony_ci
137e41f4b71Sopenharmony_ci1. Describes the dependency (deps) between modules.
138e41f4b71Sopenharmony_ci   
139e41f4b71Sopenharmony_ci   In practice, the most common problem is lack of dependency.
140e41f4b71Sopenharmony_ci
141e41f4b71Sopenharmony_ci2. Defines the module build rules (rule).
142e41f4b71Sopenharmony_ci   
143e41f4b71Sopenharmony_ci   In practice, unclear input and output are common problems.
144e41f4b71Sopenharmony_ci
145e41f4b71Sopenharmony_ciLack of dependency leads to the following problems:
146e41f4b71Sopenharmony_ci
147e41f4b71Sopenharmony_ci- Unexpected compilation error
148e41f4b71Sopenharmony_ci  
149e41f4b71Sopenharmony_ci  ```shell
150e41f4b71Sopenharmony_ci  # Example 6
151e41f4b71Sopenharmony_ci  # Lack of dependency poses a possibility of compilation errors.
152e41f4b71Sopenharmony_ci  shared_library("a") {
153e41f4b71Sopenharmony_ci    ...
154e41f4b71Sopenharmony_ci  }
155e41f4b71Sopenharmony_ci  shared_library("b") {
156e41f4b71Sopenharmony_ci    ...
157e41f4b71Sopenharmony_ci    ldflags = [ "-la" ]
158e41f4b71Sopenharmony_ci    deps = []
159e41f4b71Sopenharmony_ci    ...
160e41f4b71Sopenharmony_ci  }
161e41f4b71Sopenharmony_ci  group("images") {
162e41f4b71Sopenharmony_ci    deps = [ ":b" ]
163e41f4b71Sopenharmony_ci  }
164e41f4b71Sopenharmony_ci  ```
165e41f4b71Sopenharmony_ci  
166e41f4b71Sopenharmony_ci  In this example, **libb.so** is linked to **liba.so**, which means that **b** depends on **a**. However, the dependency of **b** on **a** is not declared in the dependency list (**deps**) of **b**. Compilation is performed concurrently. An error occurs if **liba.so** is not available when **libb.so** attempts to create a link to it.
167e41f4b71Sopenharmony_ci  
168e41f4b71Sopenharmony_ci  If **liba.so** is available, the compilation is successful. Therefore, lack of dependency poses a possibility of compilation errors.
169e41f4b71Sopenharmony_ci
170e41f4b71Sopenharmony_ci- Missing compilation of modules
171e41f4b71Sopenharmony_ci  
172e41f4b71Sopenharmony_ci  In example 6, images are the target to build. Since images depend only on **b**, **a** will not be compiled. However, as **b** depends on **a**, an error occurs when **b** is linked.
173e41f4b71Sopenharmony_ci
174e41f4b71Sopenharmony_ciAnother problem is unnecessary dependencies. Unnecessary dependencies reduce concurrency and slow down compilation. The following is an example:
175e41f4b71Sopenharmony_ci
176e41f4b71Sopenharmony_ci**_compile_js_target** does not necessarily depend on **_compile_resource_target**. If this dependency is added, **_compile_js_target** can be compiled only after **_compile_resource_target** is compiled.
177e41f4b71Sopenharmony_ci
178e41f4b71Sopenharmony_ci```shell
179e41f4b71Sopenharmony_ci# Example 7:
180e41f4b71Sopenharmony_ci# Unnecessary dependencies slow down compilation.
181e41f4b71Sopenharmony_citemplate("too_much_deps") {
182e41f4b71Sopenharmony_ci  ...
183e41f4b71Sopenharmony_ci  _gen_resource_target = "${target_name}__res"
184e41f4b71Sopenharmony_ci  action(_gen_resource_target) {
185e41f4b71Sopenharmony_ci    ...
186e41f4b71Sopenharmony_ci  }
187e41f4b71Sopenharmony_ci
188e41f4b71Sopenharmony_ci  _compile_resource_target = "${target_name}__compile_res"
189e41f4b71Sopenharmony_ci  action(_compile_resource_target) {
190e41f4b71Sopenharmony_ci    deps = [":$_gen_resource_target"]
191e41f4b71Sopenharmony_ci    ...
192e41f4b71Sopenharmony_ci  }
193e41f4b71Sopenharmony_ci
194e41f4b71Sopenharmony_ci  _compile_js_target = "${target_name}__js"
195e41f4b71Sopenharmony_ci  action(_compile_js_target) {
196e41f4b71Sopenharmony_ci    # This deps is not required.
197e41f4b71Sopenharmony_ci    deps = [":$_compile_resource_target"]
198e41f4b71Sopenharmony_ci  }
199e41f4b71Sopenharmony_ci}
200e41f4b71Sopenharmony_ci```
201e41f4b71Sopenharmony_ci
202e41f4b71Sopenharmony_ciUnclear input leads to the following problems:
203e41f4b71Sopenharmony_ci
204e41f4b71Sopenharmony_ci- Modified code is not compiled during incremental compilation.
205e41f4b71Sopenharmony_ci- The cache being used is still hit after the code is changed.
206e41f4b71Sopenharmony_ci
207e41f4b71Sopenharmony_ciIn the following example, **foo.py** references the functions in **bar.py**. This means **bar.py** is the input of **foo.py**. You need to add **bar.py** to **input** or **depfile** of **implict_input_action**. Otherwise, if **bar.py** is modified, **implict_input_action** will not be recompiled.
208e41f4b71Sopenharmony_ci
209e41f4b71Sopenharmony_ci```shell
210e41f4b71Sopenharmony_ci# Example 8:
211e41f4b71Sopenharmony_ciaction("implict_input_action") {
212e41f4b71Sopenharmony_ci  script = "//path-to-foo.py"
213e41f4b71Sopenharmony_ci  ...
214e41f4b71Sopenharmony_ci}
215e41f4b71Sopenharmony_ci```
216e41f4b71Sopenharmony_ci
217e41f4b71Sopenharmony_ci```shell
218e41f4b71Sopenharmony_ci#!/usr/bin/env
219e41f4b71Sopenharmony_ci# Content of foo.py
220e41f4b71Sopenharmony_ciimport bar
221e41f4b71Sopenharmony_ci...
222e41f4b71Sopenharmony_cibar.some_function()
223e41f4b71Sopenharmony_ci...
224e41f4b71Sopenharmony_ci```
225e41f4b71Sopenharmony_ci
226e41f4b71Sopenharmony_ciUnclear output leads to the following problems:
227e41f4b71Sopenharmony_ci
228e41f4b71Sopenharmony_ci- Implicit output
229e41f4b71Sopenharmony_ci- A failure to obtain the implicit output from the cache
230e41f4b71Sopenharmony_ci
231e41f4b71Sopenharmony_ciIn the following example, **foo.py** generates two files: **a.out** and **b.out**. However, the output of **implict_output_action** declares only **a.out**. In this case, **b.out** is an implicit output, and the cache stores only **a.out**. When the cache is hit, **b.out** cannot be compiled.
232e41f4b71Sopenharmony_ci
233e41f4b71Sopenharmony_ci```shell
234e41f4b71Sopenharmony_ci# Example 9
235e41f4b71Sopenharmony_ciaction("implict_output_action") {
236e41f4b71Sopenharmony_ci  outputs = ["${target_out_dir}/a.out"]
237e41f4b71Sopenharmony_ci  script = "//path-to-foo.py"
238e41f4b71Sopenharmony_ci  ...
239e41f4b71Sopenharmony_ci}
240e41f4b71Sopenharmony_ci```
241e41f4b71Sopenharmony_ci
242e41f4b71Sopenharmony_ci```shell
243e41f4b71Sopenharmony_ci#!/usr/bin/env
244e41f4b71Sopenharmony_ci# Content of foo.py
245e41f4b71Sopenharmony_ci...
246e41f4b71Sopenharmony_ciwrite_file("b.out")
247e41f4b71Sopenharmony_ciwrite_file("a.out")
248e41f4b71Sopenharmony_ci...
249e41f4b71Sopenharmony_ci```
250e41f4b71Sopenharmony_ci
251e41f4b71Sopenharmony_ci### Templates
252e41f4b71Sopenharmony_ci
253e41f4b71Sopenharmony_ci**Do not use GN native templates. Use the templates provided by the build system.**
254e41f4b71Sopenharmony_ci
255e41f4b71Sopenharmony_ciThe GN native templates include **source_set**, **shared_library**, **static_library**, **action**, **executable** and **group**.
256e41f4b71Sopenharmony_ci
257e41f4b71Sopenharmony_ciThe native templates are not recommended due to the following reasons:
258e41f4b71Sopenharmony_ci
259e41f4b71Sopenharmony_ci- The native templates provide only the minimal build configuration. They cannot provide functions, such as parsing **external_deps**, collecting notice, and generating installation information.
260e41f4b71Sopenharmony_ci
261e41f4b71Sopenharmony_ci- The native **action** template cannot automatically detect the changes in the dependencies of the input file, and cannot start recompilation. See Example 8.
262e41f4b71Sopenharmony_ci
263e41f4b71Sopenharmony_ci  The table below lists the mapping between the GN native templates and templates provided by OpenHarmony Compilation and Build subsystem.
264e41f4b71Sopenharmony_ci
265e41f4b71Sopenharmony_ci| OpenHarmony Template  | GN Native Template      |
266e41f4b71Sopenharmony_ci| :------------------ | -------------- |
267e41f4b71Sopenharmony_ci| ohos_shared_library | shared_library |
268e41f4b71Sopenharmony_ci| ohos_source_set     | source_set     |
269e41f4b71Sopenharmony_ci| ohos_executable     | executable     |
270e41f4b71Sopenharmony_ci| ohos_static_library | static_library |
271e41f4b71Sopenharmony_ci| action_with_pydeps  | action         |
272e41f4b71Sopenharmony_ci| ohos_group          | group          |
273e41f4b71Sopenharmony_ci
274e41f4b71Sopenharmony_ci### Using Python Scripts
275e41f4b71Sopenharmony_ci
276e41f4b71Sopenharmony_ciYou are advised to use Python scripts instead of shell scripts in **action**. Compared with shell scripts, Python scripts feature:
277e41f4b71Sopenharmony_ci
278e41f4b71Sopenharmony_ci- More user-friendly syntax, which eliminates errors caused by lack of a space
279e41f4b71Sopenharmony_ci- Easier to read
280e41f4b71Sopenharmony_ci- Easier to maintain and debug
281e41f4b71Sopenharmony_ci- Faster compilation due to caching of Python tasks
282e41f4b71Sopenharmony_ci
283e41f4b71Sopenharmony_ci### rebase_path
284e41f4b71Sopenharmony_ci
285e41f4b71Sopenharmony_ci- Call **rebase_path** only in **args** of **action**.
286e41f4b71Sopenharmony_ci  
287e41f4b71Sopenharmony_ci  ```shell
288e41f4b71Sopenharmony_ci  # Example 10
289e41f4b71Sopenharmony_ci  template("foo") {
290e41f4b71Sopenharmony_ci    action(target_name) {
291e41f4b71Sopenharmony_ci      ...
292e41f4b71Sopenharmony_ci      args = [
293e41f4b71Sopenharmony_ci        # Call rebase_path only in args.
294e41f4b71Sopenharmony_ci        "--bar=" + rebase_path(invoker.bar, root_build_dir),
295e41f4b71Sopenharmony_ci        ...
296e41f4b71Sopenharmony_ci      ]
297e41f4b71Sopenharmony_ci      ...
298e41f4b71Sopenharmony_ci    }
299e41f4b71Sopenharmony_ci  }
300e41f4b71Sopenharmony_ci  
301e41f4b71Sopenharmony_ci  foo("good") {
302e41f4b71Sopenharmony_ci    bar = something
303e41f4b71Sopenharmony_ci    ...
304e41f4b71Sopenharmony_ci  }
305e41f4b71Sopenharmony_ci  ```
306e41f4b71Sopenharmony_ci
307e41f4b71Sopenharmony_ci- If rebase_path is called twice for the same variable, unexpected results occur.
308e41f4b71Sopenharmony_ci  
309e41f4b71Sopenharmony_ci  ```shell
310e41f4b71Sopenharmony_ci  # Example 11
311e41f4b71Sopenharmony_ci  template("foo") {
312e41f4b71Sopenharmony_ci    action(target_name) {
313e41f4b71Sopenharmony_ci      ...
314e41f4b71Sopenharmony_ci      args = [
315e41f4b71Sopenharmony_ci        # After rebase_path is called twice for bar, the bar value passed is incorrect.
316e41f4b71Sopenharmony_ci        "--bar=" + rebase_path(invoker.bar, root_build_dir),
317e41f4b71Sopenharmony_ci        ...
318e41f4b71Sopenharmony_ci      ]
319e41f4b71Sopenharmony_ci      ...
320e41f4b71Sopenharmony_ci    }
321e41f4b71Sopenharmony_ci  }
322e41f4b71Sopenharmony_ci  
323e41f4b71Sopenharmony_ci  foo("bad") {
324e41f4b71Sopenharmony_ci    # Do not call rebase_path here.
325e41f4b71Sopenharmony_ci    bar = rebase_path(some_value, root_build_dir)
326e41f4b71Sopenharmony_ci    ...
327e41f4b71Sopenharmony_ci  }
328e41f4b71Sopenharmony_ci  ```
329e41f4b71Sopenharmony_ci
330e41f4b71Sopenharmony_ci### Sharing Data Between Modules
331e41f4b71Sopenharmony_ci
332e41f4b71Sopenharmony_ciIt is common to share data between modules. For example, module A wants to know the output and **deps** of module B.
333e41f4b71Sopenharmony_ci
334e41f4b71Sopenharmony_ci- Data sharing within the same **BUILD.gn**
335e41f4b71Sopenharmony_ci  
336e41f4b71Sopenharmony_ci  Data in the same **BUILD.gn** can be shared by defining global variables.
337e41f4b71Sopenharmony_ci  
338e41f4b71Sopenharmony_ci  In the following example, the output of module **a** is the input of module **b**, and can be shared with module **b** via global variables.
339e41f4b71Sopenharmony_ci  
340e41f4b71Sopenharmony_ci  ```shell
341e41f4b71Sopenharmony_ci  # Example 12
342e41f4b71Sopenharmony_ci  _output_a = get_label_info(":a", "out_dir") + "/a.out"
343e41f4b71Sopenharmony_ci  action("a") {
344e41f4b71Sopenharmony_ci    outputs = _output_a
345e41f4b71Sopenharmony_ci    ...
346e41f4b71Sopenharmony_ci  }
347e41f4b71Sopenharmony_ci  action("b") {
348e41f4b71Sopenharmony_ci    inputs = [_output_a]
349e41f4b71Sopenharmony_ci    ...
350e41f4b71Sopenharmony_ci  }
351e41f4b71Sopenharmony_ci  ```
352e41f4b71Sopenharmony_ci
353e41f4b71Sopenharmony_ci- Data sharing between different **BUILD.gn**s
354e41f4b71Sopenharmony_ci  
355e41f4b71Sopenharmony_ci  The best way to share data between different **BUILD.gn** is to save the data as files and transfer the files between modules. You can refer to **write_meta_data** in the OpenHarmony HAP build process.
356e41f4b71Sopenharmony_ci
357e41f4b71Sopenharmony_ci### forward_variable_from
358e41f4b71Sopenharmony_ci
359e41f4b71Sopenharmony_ci- To customize a template, pass (**forward**) **testonly** first because the **testonly** target may depend on the template target.
360e41f4b71Sopenharmony_ci  
361e41f4b71Sopenharmony_ci  ```shell
362e41f4b71Sopenharmony_ci  # Example 13
363e41f4b71Sopenharmony_ci  # For a customized template, pass testonly first.
364e41f4b71Sopenharmony_ci  template("foo") {
365e41f4b71Sopenharmony_ci    forward_variable_from(invoker, ["testonly"])
366e41f4b71Sopenharmony_ci    ...
367e41f4b71Sopenharmony_ci  }
368e41f4b71Sopenharmony_ci  ```
369e41f4b71Sopenharmony_ci
370e41f4b71Sopenharmony_ci- Do not use asterisks (*) to **forward** variables. Required variables must be explicitly forwarded one by one.
371e41f4b71Sopenharmony_ci  
372e41f4b71Sopenharmony_ci  ```shell
373e41f4b71Sopenharmony_ci  # Example 14
374e41f4b71Sopenharmony_ci  # Bad. The asterisk (*) is used to forward the variable.
375e41f4b71Sopenharmony_ci  template("foo") {
376e41f4b71Sopenharmony_ci    forward_variable_from(invoker, "*")
377e41f4b71Sopenharmony_ci    ...
378e41f4b71Sopenharmony_ci  }
379e41f4b71Sopenharmony_ci  
380e41f4b71Sopenharmony_ci  # Good. Variables are explicitly forwarded one by one.
381e41f4b71Sopenharmony_ci  template("bar") {
382e41f4b71Sopenharmony_ci    # 
383e41f4b71Sopenharmony_ci    forward_variable_from(invoker, [
384e41f4b71Sopenharmony_ci                                       "testonly",
385e41f4b71Sopenharmony_ci                                       "deps",
386e41f4b71Sopenharmony_ci                                       ...
387e41f4b71Sopenharmony_ci                                     ])
388e41f4b71Sopenharmony_ci    ...
389e41f4b71Sopenharmony_ci  }
390e41f4b71Sopenharmony_ci  ```
391e41f4b71Sopenharmony_ci
392e41f4b71Sopenharmony_ci### target_name
393e41f4b71Sopenharmony_ci
394e41f4b71Sopenharmony_ciThe value of **target_name** varies with the scope.
395e41f4b71Sopenharmony_ci
396e41f4b71Sopenharmony_ci```shell
397e41f4b71Sopenharmony_ci# Example 15
398e41f4b71Sopenharmony_ci# The value of target_name varies with the scope.
399e41f4b71Sopenharmony_citemplate("foo") {
400e41f4b71Sopenharmony_ci  # The displayed target_name is "${target_name}".
401e41f4b71Sopenharmony_ci  print(target_name)
402e41f4b71Sopenharmony_ci  _code_gen_target = "${target_name}__gen"
403e41f4b71Sopenharmony_ci  code_gen(_code_gen_target) {
404e41f4b71Sopenharmony_ci    # The displayed target_name is "${target_name}__gen".
405e41f4b71Sopenharmony_ci    print(target_name)
406e41f4b71Sopenharmony_ci    ...
407e41f4b71Sopenharmony_ci  }
408e41f4b71Sopenharmony_ci  _compile_gen_target = "${target_name}__compile"
409e41f4b71Sopenharmony_ci  compile(_compile_gen_target) {
410e41f4b71Sopenharmony_ci    # The displayed target_name is "${target_name}__compile".
411e41f4b71Sopenharmony_ci    print(target_name)
412e41f4b71Sopenharmony_ci    ...
413e41f4b71Sopenharmony_ci  }
414e41f4b71Sopenharmony_ci  ...
415e41f4b71Sopenharmony_ci}
416e41f4b71Sopenharmony_ci```
417e41f4b71Sopenharmony_ci
418e41f4b71Sopenharmony_ci### public_configs
419e41f4b71Sopenharmony_ci
420e41f4b71Sopenharmony_ciTo export header files from a module, use **public_configs**.
421e41f4b71Sopenharmony_ci
422e41f4b71Sopenharmony_ci```shell
423e41f4b71Sopenharmony_ci# Example 16
424e41f4b71Sopenharmony_ci# b depends on a and inherits from the headers of a.
425e41f4b71Sopenharmony_ciconfig("headers") {
426e41f4b71Sopenharmony_ci  include_dirs = ["//path-to-headers"]
427e41f4b71Sopenharmony_ci  ...
428e41f4b71Sopenharmony_ci}
429e41f4b71Sopenharmony_cishared_library("a") {
430e41f4b71Sopenharmony_ci  public_configs = [":headers"]
431e41f4b71Sopenharmony_ci  ...
432e41f4b71Sopenharmony_ci}
433e41f4b71Sopenharmony_ciexecutable("b") {
434e41f4b71Sopenharmony_ci  deps = [":a"]
435e41f4b71Sopenharmony_ci  ...
436e41f4b71Sopenharmony_ci}
437e41f4b71Sopenharmony_ci```
438e41f4b71Sopenharmony_ci
439e41f4b71Sopenharmony_ci### template
440e41f4b71Sopenharmony_ci
441e41f4b71Sopenharmony_ciA custom template must contain a subtarget named **target_name**. This subtarget is used as the target of the template and depends on other subtargets. Otherwise, the subtargets will not be compiled.
442e41f4b71Sopenharmony_ci
443e41f4b71Sopenharmony_ci```shell
444e41f4b71Sopenharmony_ci# Example 17
445e41f4b71Sopenharmony_ci# A custom template must have a subtarget named target_name.
446e41f4b71Sopenharmony_citemplate("foo") {
447e41f4b71Sopenharmony_ci  _code_gen_target = "${target_name}__gen"
448e41f4b71Sopenharmony_ci  code_gen(_code_gen_target) {
449e41f4b71Sopenharmony_ci    ...
450e41f4b71Sopenharmony_ci  }
451e41f4b71Sopenharmony_ci  _compile_gen_target = "${target_name}__compile"
452e41f4b71Sopenharmony_ci  compile(_compile_gen_target) {
453e41f4b71Sopenharmony_ci    # The displayed target_name is "${target_name}__compile".
454e41f4b71Sopenharmony_ci    print(target_name)
455e41f4b71Sopenharmony_ci    ...
456e41f4b71Sopenharmony_ci  }
457e41f4b71Sopenharmony_ci  ...
458e41f4b71Sopenharmony_ci  group(target_name) {
459e41f4b71Sopenharmony_ci    deps = [
460e41f4b71Sopenharmony_ci    # _compile_gen_target depends on _code_gen_target. Therefore, target_name only needs to depend on _compile_gen_target.
461e41f4b71Sopenharmony_ci      ":$_compile_gen_target"
462e41f4b71Sopenharmony_ci    ]
463e41f4b71Sopenharmony_ci  }
464e41f4b71Sopenharmony_ci}
465e41f4b71Sopenharmony_ci```
466e41f4b71Sopenharmony_ci
467e41f4b71Sopenharmony_ci### set_source_assignment_filter
468e41f4b71Sopenharmony_ci
469e41f4b71Sopenharmony_ciIn addition to **sources**, **set_source_assignment_filter** can be used to filter other variables. After the filtering is complete, clear the filter and **sources**.
470e41f4b71Sopenharmony_ci
471e41f4b71Sopenharmony_ci```shell
472e41f4b71Sopenharmony_ci# Example 18
473e41f4b71Sopenharmony_ci# Use set_source_assignment_filter to filter dependencies and add the dependencies with labels matching *:*_res to the dependency list.
474e41f4b71Sopenharmony_ci_deps = []
475e41f4b71Sopenharmony_ciforeach(_possible_dep, invoker.deps) {
476e41f4b71Sopenharmony_ci  set_source_assignment_filter(["*:*_res"])
477e41f4b71Sopenharmony_ci  _label = get_label_info(_possible_dep, "label_no_toolchain")
478e41f4b71Sopenharmony_ci  sources = []
479e41f4b71Sopenharmony_ci  sources = [ _label ]
480e41f4b71Sopenharmony_ci  if (sources = []) {
481e41f4b71Sopenharmony_ci    _deps += _sources
482e41f4b71Sopenharmony_ci  }
483e41f4b71Sopenharmony_ci}
484e41f4b71Sopenharmony_cisources = []
485e41f4b71Sopenharmony_ciset_source_assignment_filter([])
486e41f4b71Sopenharmony_ci```
487e41f4b71Sopenharmony_ci
488e41f4b71Sopenharmony_ciIn the latest version, **set_source_assignment_filter** is replaced by **filter_include** and **filter_exclude**.
489e41f4b71Sopenharmony_ci
490e41f4b71Sopenharmony_ci### Setting deps and external_deps
491e41f4b71Sopenharmony_ci
492e41f4b71Sopenharmony_ciAn OpenHarmony component is a group of modules that can provide a capability. When defining a module, set **part_name** to specify the component to which the module belongs.
493e41f4b71Sopenharmony_ci
494e41f4b71Sopenharmony_ciYou must also declare **inner_kits** of a component for other components to call. For details, see **bundle.json** in the source code. **inner_kits** applies only to dependent modules in different components.
495e41f4b71Sopenharmony_ci
496e41f4b71Sopenharmony_ciIf modules **a** and **b** has the same **part_name**, modules **a** and **b** belong to the same component. In this case, declare the dependency between them using **deps**.
497e41f4b71Sopenharmony_ci
498e41f4b71Sopenharmony_ciIf modules **a** and **b** have different **part_name**, modules **a** and **b** belong to different components. In this case, declare the dependency between them using **external_deps** in the *Component name:Module name* format. See Example 19.
499e41f4b71Sopenharmony_ci
500e41f4b71Sopenharmony_ci```shell
501e41f4b71Sopenharmony_ci# Example 19
502e41f4b71Sopenharmony_cishared_library("a") {
503e41f4b71Sopenharmony_ci  ...
504e41f4b71Sopenharmony_ci  external_deps = ["part_name_of_b:b"]
505e41f4b71Sopenharmony_ci  ...
506e41f4b71Sopenharmony_ci}
507e41f4b71Sopenharmony_ci```