1# Copyright (c) 2021 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/config/python.gni")
15import("//build/ohos/app/app_internal.gni")
16import("//build/ohos/notice/notice.gni")
17import("//build/ohos_var.gni")
18import("//build/templates/common/collect_target.gni")
19import("//build/templates/metadata/module_info.gni")
20
21declare_args() {
22  app_need_publicity = false
23}
24
25# Declare an OHOS AppScope target
26#
27# Variables:
28#   app_profile: common config of hap.
29#   sources: list of asset files to be included in hap.
30#
31template("ohos_app_scope") {
32  forward_variables_from(invoker, [ "testonly" ])
33  assert(defined(invoker.app_profile),
34         "app_profile must be defined for ohos_app_scope")
35  assert(defined(invoker.sources), "sources must be defined for ohos_app_scope")
36
37  _metadata = "$target_gen_dir/$target_name.metadata"
38  _metadata_target = "${target_name}__metadata"
39  write_meta_data(_metadata_target) {
40    forward_variables_from(invoker, [ "app_profile" ])
41    type = "app_profile"
42    meta_data = _metadata
43    resources = invoker.sources
44    app_profile = invoker.app_profile
45  }
46  group(target_name) {
47    public_deps = [ ":$_metadata_target" ]
48  }
49}
50
51# Declare an OHOS assets target
52#
53# Variables:
54#   deps: dependencies of this target.
55#   sources: list of asset files to be included in hap.
56#
57template("ohos_assets") {
58  forward_variables_from(invoker, [ "testonly" ])
59  assert(defined(invoker.sources), "sources must be defined for ohos_assets")
60  _metadata = "$target_gen_dir/$target_name.metadata"
61
62  _metadata_target = "${target_name}__metadata"
63  write_meta_data(_metadata_target) {
64    forward_variables_from(invoker, [ "deps" ])
65    type = "assets"
66    meta_data = _metadata
67    raw_assets = invoker.sources
68  }
69  group(target_name) {
70    public_deps = [ ":$_metadata_target" ]
71  }
72}
73
74# Declare a js assets target
75#
76# Variables:
77#   source_dir: js assets directory, only one directory supported, string not list.
78#   js2abc: whether to transform js bundle to ark bytecode, default value
79#             follows build_ark.
80#   ets2abc: whether to transform ets bundle to ark bytecode, default value false
81#   deps: dependencies of this target.
82#
83template("ohos_js_assets") {
84  forward_variables_from(invoker, [ "testonly" ])
85  assert(defined(invoker.source_dir),
86         "source_dir must be defined for ohos_js_assets")
87
88  _metadata = "$target_gen_dir/$target_name.metadata"
89  _metadata_target = "${target_name}__metadata"
90  write_meta_data(_metadata_target) {
91    forward_variables_from(invoker,
92                           [
93                             "source_dir",
94                             "deps",
95                           ])
96    meta_data = _metadata
97    if (defined(invoker.ets2abc) && invoker.ets2abc) {
98      type = "ets_assets"
99      ets_assets = [ source_dir ]
100    } else if (defined(invoker.js2abc) && invoker.js2abc) {
101      type = "js_assets"
102      js_assets = [ source_dir ]
103    } else {
104      type = "unresolved_assets"
105      unresolved_assets = [ source_dir ]
106    }
107    if (defined(invoker.hap_profile)) {
108      hap_profile = invoker.hap_profile
109    }
110  }
111  group(target_name) {
112    public_deps = [ ":$_metadata_target" ]
113  }
114}
115
116# Declare an OHOS resource target
117#
118# Variables:
119#   deps: dependencies of this target.
120#   sources: list of resource files to be compiled.
121#   hap_profile: hap_profile is used when building resources.
122#
123template("ohos_resources") {
124  forward_variables_from(invoker, [ "testonly" ])
125  assert(defined(invoker.sources), "sources must be defined for ohos_resources")
126  _metadata = "$target_gen_dir/$target_name.metadata"
127
128  _deps = []
129  if (defined(invoker.deps)) {
130    _deps += invoker.deps
131  }
132
133  module_config = ""
134  module_configs = string_split(invoker.hap_profile, "/")
135  foreach(_module_config, module_configs) {
136    module_config = _module_config
137  }
138  _generated_profile = "$target_gen_dir/${target_name}/${module_config}"
139  _metadata_target = "${target_name}__metadata"
140  write_meta_data(_metadata_target) {
141    forward_variables_from(invoker, [ "package_name" ])
142    type = "resources"
143    meta_data = _metadata
144    resources = invoker.sources
145    hap_profile = _generated_profile
146    deps = _deps
147    possible_deps = _deps
148  }
149
150  _deps += [ ":$_metadata_target" ]
151
152  # compile_resources target here only used for concat app.json to module.json
153  _compile_profile_target = "${target_name}__compile_profile"
154  merge_profile(_compile_profile_target) {
155    forward_variables_from(invoker,
156                           [
157                             "deps",
158                             "hap_profile",
159                           ])
160    meta_data = _metadata
161    generated_profile = _generated_profile
162    if (defined(deps)) {
163      deps += _deps
164    } else {
165      deps = _deps
166    }
167  }
168
169  _deps += [ ":$_compile_profile_target" ]
170
171  # compile_resources target here only used for resources.h generation
172  _compile_resources_target = "${target_name}__compile_resources"
173  _generated_header_dir = "$target_gen_dir/$target_name"
174  compile_resources(_compile_resources_target) {
175    forward_variables_from(invoker,
176                           [
177                             "deps",
178                             "package_name",
179                           ])
180    hap_profile = _generated_profile
181    meta_data = _metadata
182    generated_header_dir = _generated_header_dir
183    if (defined(deps)) {
184      deps += _deps
185    } else {
186      deps = _deps
187    }
188  }
189
190  _resources_config = "${target_name}__resources_headers"
191  config(_resources_config) {
192    include_dirs = [ _generated_header_dir ]
193  }
194
195  group(target_name) {
196    public_deps = [ ":$_metadata_target" ]
197    deps = [
198      ":$_compile_profile_target",
199      ":$_compile_resources_target",
200    ]
201    public_configs = [ ":$_resources_config" ]
202  }
203}
204
205if (app_need_publicity) {
206  template("_ohos_publicity") {
207    forward_variables_from(invoker,
208                           [
209                             "_hap_name",
210                             "module_install_dir",
211                             "relative_install_dir",
212                           ])
213
214    action(target_name) {
215      script = "//build/scripts/collect_publicity.py"
216      module_type = "app"
217      if (defined(module_install_dir)) {
218        not_needed([ "relative_install_dir" ])
219        install_dir = string_replace(module_install_dir, "${module_type}/", "")
220      } else if (defined(relative_install_dir)) {
221        install_dir = relative_install_dir
222      } else {
223        install_dir = ""
224      }
225
226      if (install_dir == "") {
227        print(
228            "${invoker.module_label} not set install dir, empty install dir is invalid.")
229      }
230      args = []
231      if (defined(invoker.publicity_file)) {
232        inputs = [ invoker.publicity_file ]
233        source = inputs[0]
234        args += [
235          "--source",
236          rebase_path(source, root_build_dir),
237        ]
238      } else {
239        print("${invoker.module_label} need to set publicity_file.")
240      }
241      outputs = [ "${root_build_dir}/app_publicity/${install_dir}/${_hap_name}_publicity.xml" ]
242      args += [
243        "--output",
244        rebase_path(outputs[0], root_build_dir),
245      ]
246    }
247  }
248}
249
250template("ohos_app") {
251  forward_variables_from(invoker,
252                         [
253                           "testonly",
254                           "install_enable",
255                           "install_images",
256                           "module_install_dir",
257                           "relative_install_dir",
258                         ])
259
260  _test_target = defined(testonly) && testonly
261  _unsigned_hap_path_list =
262      "${target_out_dir}/${target_name}/unsigned_hap_path_list.json"
263
264  _abs_path = get_path_info("./", "abspath")
265  _hap_out_dir = "${target_out_dir}/${target_name}"
266  if (defined(invoker.hap_out_dir)) {
267    _hap_out_dir = invoker.hap_out_dir
268  }
269
270  _hap_name = target_name
271  if (defined(invoker.hap_name)) {
272    _hap_name = invoker.hap_name
273  }
274
275  if (defined(invoker.build_profile)) {
276    build_profile = invoker.build_profile
277  } else {
278    build_profile = "./build-profile.json5"
279  }
280
281  _js_build_mode = "release"
282  if (defined(invoker.js_build_mode)) {
283    _js_build_mode = invoker.js_build_mode
284  }
285
286  if (defined(invoker.system_lib_deps)) {
287    _system_lib_deps = invoker.system_lib_deps
288  }
289
290  _main_target_name = target_name
291
292  if (defined(invoker.subsystem_name) && defined(invoker.part_name)) {
293    _subsystem_name = invoker.subsystem_name
294    _part_name = invoker.part_name
295  } else if (defined(invoker.part_name)) {
296    _part_name = invoker.part_name
297    _part_subsystem_info_file =
298        "$root_build_dir/build_configs/parts_info/part_subsystem.json"
299    _arguments = [
300      "--part-name",
301      _part_name,
302      "--part-subsystem-info-file",
303      rebase_path(_part_subsystem_info_file, root_build_dir),
304    ]
305    _get_subsystem_script = "//build/templates/common/get_subsystem_name.py"
306    _subsystem_name =
307        exec_script(_get_subsystem_script, _arguments, "trim string")
308  } else if (defined(invoker.subsystem_name)) {
309    _subsystem_name = invoker.subsystem_name
310    _part_name = _subsystem_name
311  } else {
312    _subsystem_name = "build"
313    _part_name = "build_framework"
314  }
315
316  assert(_subsystem_name != "")  # Mark as used
317  assert(_part_name != "")  # Mark as used
318
319  module_label = get_label_info(":${target_name}", "label_with_toolchain")
320  _collect_target = "${target_name}__collect"
321  collect_module_target(_collect_target) {
322    forward_variables_from(invoker, [ "install_images" ])
323  }
324
325  if (!defined(install_enable)) {
326    install_enable = true
327  }
328
329  if (!_test_target) {
330    if (defined(install_images)) {
331      app_allow_images = [ "system" ]
332      allow_image = filter_exclude(install_images, app_allow_images)
333      assert(
334          allow_image == [],
335          "${module_label} has invaild install_images: ${invoker.install_images}, allowed values: ${app_allow_images}")
336    }
337
338    if (defined(module_install_dir)) {
339      app_allow_path = [ "app/*" ]
340      if (filter_exclude([ module_install_dir ], app_allow_path) != [] ||
341          module_install_dir == "app/") {
342        assert(
343            false,
344            "${module_label} has invaild module_install_dir: ${invoker.module_install_dir}, allowed values: app/{{app_name}}")
345      }
346    }
347
348    if (!defined(module_install_dir) && !defined(relative_install_dir)) {
349      print(
350          "Set module_install_dir or relative_install_dir field in the ${module_label}. Do not install the module to app.")
351    }
352
353    if (app_need_publicity) {
354      if (install_enable) {
355        _publicity_target = "${_main_target_name}_publicity"
356        _ohos_publicity(_publicity_target) {
357          forward_variables_from(invoker, [ "publicity_file" ])
358        }
359      }
360    }
361  }
362
363  _module_info_target = "${_main_target_name}_info"
364  generate_module_info(_module_info_target) {
365    module_name = _main_target_name
366    module_type = "app"
367    module_source_dir = get_path_info(_hap_out_dir, "dir")
368
369    if (defined(invoker.install_images)) {
370      module_install_images = []
371      module_install_images += invoker.install_images
372    } else {
373      module_install_images = [ "system" ]
374    }
375
376    if (defined(invoker.symlink_target_name)) {
377      symlink_target_name = invoker.symlink_target_name
378    }
379
380    notice = "$target_out_dir/$_main_target_name.notice.txt"
381  }
382
383  _notice_target = "${target_name}_notice"
384  collect_notice(_notice_target) {
385    forward_variables_from(invoker,
386                           [
387                             "license_as_sources",
388                             "license_file",
389                           ])
390    module_name = _main_target_name
391    module_type = "app"
392    module_source_dir = get_label_info(":${_main_target_name}", "dir")
393  }
394
395  _compile_app_target = "${target_name}_compile_app"
396  compile_app(_compile_app_target) {
397    build_mode = _js_build_mode
398    cwd = _abs_path
399    unsigned_hap_path_list = _unsigned_hap_path_list
400    deps = [
401      ":${_collect_target}",
402      ":${_notice_target}",
403    ]
404
405    if (!_test_target && app_need_publicity) {
406      if (install_enable) {
407        deps += [ ":${_publicity_target}" ]
408      } else {
409        if (defined(invoker.publicity_file)) {
410          print(
411              "${module_label} is not install, please delete set publicity_file: ${invoker.publicity_file}.")
412        }
413      }
414    } else {
415      if (defined(invoker.publicity_file)) {
416        not_needed(invoker, [ "publicity_file" ])
417      }
418    }
419    if (defined(invoker.deps)) {
420      deps += invoker.deps
421    }
422    if (defined(invoker.system_lib_deps)) {
423      system_lib_deps = _system_lib_deps
424      deps += _system_lib_deps
425    }
426    if (defined(invoker.test_hap)) {
427      test_hap = invoker.test_hap
428    }
429    if (defined(invoker.test_module)) {
430      test_module = invoker.test_module
431    }
432    if (defined(invoker.module_libs_dir)) {
433      module_libs_dir = invoker.module_libs_dir
434    }
435    if (defined(invoker.sdk_home)) {
436      sdk_home = invoker.sdk_home
437    } else {
438      sdk_home = "//prebuilts/ohos-sdk/linux"
439    }
440    if (defined(invoker.sdk_type_name)) {
441      sdk_type_name = invoker.sdk_type_name
442    }
443    if (defined(invoker.hvigor_home)) {
444      hvigor_home = invoker.hvigor_home
445    }
446    if (defined(invoker.build_modules)) {
447      build_modules = invoker.build_modules
448    }
449    if (defined(invoker.assemble_type)) {
450      assemble_type = invoker.assemble_type
451    }
452    if (defined(invoker.build_level)) {
453      build_level = invoker.build_level
454    }
455  }
456  _hap_list = "${target_out_dir}/${target_name}/hap_list.json"
457  if (defined(invoker.hap_list)) {
458    _hap_list_json = {
459      do_filter = true
460      hap_list = invoker.hap_list
461    }
462    write_file(_hap_list, _hap_list_json, "json")
463  }
464  app_sign(target_name) {
465    forward_variables_from(invoker,
466                           [
467                             "private_key_path",
468                             "signature_algorithm",
469                             "certificate_profile",
470                             "keystore_path",
471                             "keystore_password",
472                             "key_alias",
473                             "certificate_file",
474                             "compatible_version",
475                           ])
476    unsigned_hap_path_list = _unsigned_hap_path_list
477    deps = [
478      ":$_compile_app_target",
479      ":$_module_info_target",
480    ]
481    hap_out_dir = _hap_out_dir
482    hap_name = _hap_name
483    hap_list = _hap_list
484    install_module_info = {
485      module_def = get_label_info(":$target_name", "label_with_toolchain")
486      module_info_file =
487          rebase_path(get_label_info(module_def, "target_out_dir"),
488                      root_build_dir) + "/${target_name}_module_info.json"
489      toolchain = current_toolchain
490      toolchain_out_dir = rebase_path(root_out_dir, root_build_dir)
491      part_name = _part_name
492      subsystem_name = _subsystem_name
493    }
494  }
495}
496
497# Declare an OHOS hap target
498#
499# Variables:
500#   deps: dependencies of this target.
501#   hap_name: name of output hap file.
502#   final_hap_path: full path of output hap file, final_hap_path overwrites hap_name.
503#   js2abc:   whether to transform js bundle to ark bytecode, default value
504#             follows build_ark.
505#   ets2abc:   whether to transform js bundle to ark bytecode, default value false
506#
507#
508template("ohos_hap") {
509  forward_variables_from(invoker,
510                         [
511                           "testonly",
512                           "install_enable",
513                           "install_images",
514                           "module_install_dir",
515                           "relative_install_dir",
516                         ])
517  assert(defined(invoker.hap_profile),
518         "hap_profile must be defined for ohos_hap")
519
520  _test_target = defined(testonly) && testonly
521  _deps = []
522  if (defined(invoker.deps)) {
523    _deps = invoker.deps
524  }
525
526  _hap_profile = invoker.hap_profile
527  _hap_name = target_name
528  if (defined(invoker.hap_name)) {
529    _hap_name = invoker.hap_name
530  }
531
532  _hap_path = "$target_out_dir/$_hap_name.hap"
533  if (defined(invoker.final_hap_path)) {
534    _hap_path = invoker.final_hap_path
535  }
536
537  _js2abc = build_ark
538  if (defined(invoker.js2abc)) {
539    _js2abc = invoker.js2abc
540  }
541
542  _ets2abc = false
543  if (defined(invoker.ets2abc)) {
544    _ets2abc = invoker.ets2abc
545  }
546
547  if (_ets2abc) {
548    _js2abc = false
549  }
550
551  _js_build_mode = "release"
552  if (defined(invoker.js_build_mode)) {
553    _js_build_mode = invoker.js_build_mode
554  }
555
556  _main_target_name = target_name
557
558  if (defined(invoker.subsystem_name) && defined(invoker.part_name)) {
559    _subsystem_name = invoker.subsystem_name
560    _part_name = invoker.part_name
561  } else if (defined(invoker.part_name)) {
562    _part_name = invoker.part_name
563    _part_subsystem_info_file =
564        "$root_build_dir/build_configs/parts_info/part_subsystem.json"
565    _arguments = [
566      "--part-name",
567      _part_name,
568      "--part-subsystem-info-file",
569      rebase_path(_part_subsystem_info_file, root_build_dir),
570    ]
571    _get_subsystem_script = "//build/templates/common/get_subsystem_name.py"
572    _subsystem_name =
573        exec_script(_get_subsystem_script, _arguments, "trim string")
574  } else if (defined(invoker.subsystem_name)) {
575    _subsystem_name = invoker.subsystem_name
576    _part_name = _subsystem_name
577  } else {
578    _subsystem_name = "build"
579    _part_name = "build_framework"
580  }
581
582  assert(_subsystem_name != "")  # Mark as used
583  assert(_part_name != "")  # Mark as used
584
585  # metadata is used to record all necessary data for hap.
586  _metadata_target = "${target_name}__metadata"
587  _meta_data = "$target_gen_dir/$target_name.metadata"
588  write_meta_data(_metadata_target) {
589    forward_variables_from(invoker,
590                           [
591                             "raw_assets",
592                             "resources",
593                             "js_assets",
594                             "ets_assets",
595                           ])
596    hap_profile = invoker.hap_profile
597    meta_data = _meta_data
598    possible_deps = _deps
599    type = "hap"
600    js2abc = _js2abc
601    hap_path = _hap_path
602  }
603
604  _js_assets_target = "${target_name}__js_assets"
605  _packaged_js_assets = "$target_out_dir/$target_name/js_assets.zip"
606  compile_js_assets(_js_assets_target) {
607    hap_profile = _hap_profile
608    packaged_js_assets = _packaged_js_assets
609    meta_data = _meta_data
610    deps = [ ":$_metadata_target" ] + _deps
611    build_mode = _js_build_mode
612    js2abc = _js2abc
613    ets2abc = _ets2abc
614    if (defined(testonly) && testonly == true) {
615      main_target_name = _main_target_name
616    }
617  }
618
619  _resources_target = "${target_name}__compile_resources"
620  _packaged_resources = "$target_out_dir/$target_name/resources.zip"
621  _generated_header_dir = "$target_out_dir/$target_name"
622  compile_resources(_resources_target) {
623    hap_profile = _hap_profile
624    packaged_resources = _packaged_resources
625    generated_header_dir = _generated_header_dir
626    meta_data = _meta_data
627    deps = [ ":$_metadata_target" ] + _deps
628  }
629
630  module_label = get_label_info(":${target_name}", "label_with_toolchain")
631  _collect_target = "${target_name}__collect"
632  collect_module_target(_collect_target) {
633    forward_variables_from(invoker, [ "install_images" ])
634  }
635
636  _notice_target = "${target_name}__notice"
637  collect_notice(_notice_target) {
638    forward_variables_from(invoker,
639                           [
640                             "license_as_sources",
641                             "license_file",
642                           ])
643    module_type = "app"
644    module_name = _main_target_name
645    module_source_dir = get_label_info(":${_main_target_name}", "dir")
646  }
647
648  if (!defined(install_enable)) {
649    install_enable = true
650  }
651
652  if (!_test_target) {
653    if (defined(install_images)) {
654      app_allow_images = [ "system" ]
655      allow_image = filter_exclude(install_images, app_allow_images)
656      assert(
657          allow_image == [],
658          "${module_label} has invaild install_images: ${invoker.install_images}, allowed values: ${app_allow_images}")
659    }
660
661    if (defined(module_install_dir)) {
662      app_allow_path = [ "app/*" ]
663      if (filter_exclude([ module_install_dir ], app_allow_path) != [] ||
664          module_install_dir == "app/") {
665        assert(
666            false,
667            "${module_label} has invaild module_install_dir: ${invoker.module_install_dir}, allowed values: app/{{app_name}}")
668      }
669    }
670
671    if (!defined(module_install_dir) && !defined(relative_install_dir)) {
672      print(
673          "Set module_install_dir or relative_install_dir field in the ${module_label}. Do not install the module to app.")
674    }
675
676    if (app_need_publicity) {
677      if (install_enable) {
678        _publicity_target = "${_main_target_name}_publicity"
679        _ohos_publicity(_publicity_target) {
680          forward_variables_from(invoker, [ "publicity_file" ])
681        }
682      }
683    }
684  }
685
686  _module_info_target = "${_main_target_name}_info"
687  generate_module_info(_module_info_target) {
688    module_name = _main_target_name
689    module_type = "app"
690
691    module_source_dir = get_path_info(_hap_path, "dir")
692    module_install_name = get_path_info(_hap_path, "name")
693    if (defined(invoker.module_install_name)) {
694      module_install_name = invoker.module_install_name
695    }
696
697    module_install_images = [ "system" ]
698    if (defined(invoker.install_images)) {
699      module_install_images = []
700      module_install_images += invoker.install_images
701    }
702
703    module_output_extension = ".hap"
704
705    if (defined(invoker.symlink_target_name)) {
706      symlink_target_name = invoker.symlink_target_name
707    }
708    notice = "$target_out_dir/$_main_target_name.notice.txt"
709  }
710
711  package_app(target_name) {
712    forward_variables_from(invoker,
713                           [
714                             "shared_libraries",
715                             "private_key_path",
716                             "signature_algorithm",
717                             "certificate_profile",
718                             "keystore_path",
719                             "keystore_password",
720                             "key_alias",
721                             "certificate_file",
722                             "compatible_version",
723                           ])
724    deps = [
725      ":$_js_assets_target",
726      ":$_metadata_target",
727      ":$_notice_target",
728      ":$_resources_target",
729      ":${_collect_target}",
730      "//developtools/packing_tool:packing_tool",
731    ]
732    if (!_test_target && app_need_publicity) {
733      if (install_enable) {
734        deps += [ ":${_publicity_target}" ]
735      } else {
736        if (defined(invoker.publicity_file)) {
737          print(
738              "${module_label} is not install, please delete set publicity_file: ${invoker.publicity_file}.")
739        }
740      }
741    } else {
742      if (defined(invoker.publicity_file)) {
743        not_needed(invoker, [ "publicity_file" ])
744      }
745    }
746    if (!skip_gen_module_info) {
747      deps += [ ":$_module_info_target" ]
748    }
749    enable_ark = build_ark
750    if (defined(shared_libraries)) {
751      deps += shared_libraries
752    }
753    packaged_js_assets = _packaged_js_assets
754    packaged_resources = _packaged_resources
755    hap_profile = _hap_profile
756    meta_data = _meta_data
757    hap_path = _hap_path
758    build_mode = _js_build_mode
759
760    install_module_info = {
761      module_def = get_label_info(":$target_name", "label_with_toolchain")
762      module_info_file =
763          rebase_path(get_label_info(module_def, "target_out_dir"),
764                      root_build_dir) + "/${target_name}_module_info.json"
765      subsystem_name = _subsystem_name
766      part_name = _part_name
767      toolchain = current_toolchain
768      toolchain_out_dir = rebase_path(root_out_dir, root_build_dir)
769    }
770  }
771}
772