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/ohos/copy_ex.gni")
15import("//build/config/python.gni")
16import("//build/ohos/build_var.gni")
17import("//build/ohos/notice/notice.gni")
18import("//build/ohos_var.gni")
19
20declare_args() {
21  sdk_native = "sdk-native"
22  version_script_suffix = ".map.txt"
23  ndk_signature_save_dir = "//interface/sdk-native"
24  ndk_zip_prefix = "native"
25  enable_ndk_doxygen = true
26}
27
28if (use_current_sdk) {
29  # native_dir is native current-sdk release dir, all things redefine base the value.
30  native_dir = "base-current-sdk/linux/${api_version}/native"
31
32  ndk_os_irrelevant_out_dir = "$root_out_dir/${native_dir}"
33  ndk_os_specific_out_dir = "$root_out_dir/${native_dir}"
34  ndk_signature_out_dir = "$root_out_dir/${native_dir}/.others/signature"
35} else {
36  ndk_os_irrelevant_out_dir = "$root_out_dir/${sdk_native}/os-irrelevant"
37  ndk_os_specific_out_dir = "$root_out_dir/${sdk_native}/os-specific"
38  ndk_signature_out_dir = "$root_out_dir/${sdk_native}/signature"
39}
40
41ndk_headers_out_dir = "$ndk_os_irrelevant_out_dir/sysroot/usr/include"
42ndk_libraries_out_dir = "$ndk_os_irrelevant_out_dir/sysroot/usr/lib"
43ndk_docs_out_dir = "$ndk_os_irrelevant_out_dir/docs"
44
45windows_system = "windows"
46linux_system = "linux"
47darwin_system = "darwin"
48ohos_system = "ohos"
49
50if (use_current_sdk) {
51  ndk_windows_specific_out_dir =
52      "${ndk_os_specific_out_dir}/.others/${windows_system}"
53  ndk_darwin_specific_out_dir =
54      "${ndk_os_specific_out_dir}/.others/${darwin_system}"
55  ndk_linux_specific_out_dir = "${ndk_os_specific_out_dir}"
56  ndk_ohos_specific_out_dir =
57      "${ndk_os_specific_out_dir}/.others/${ohos_system}"
58} else {
59  ndk_windows_specific_out_dir = "${ndk_os_specific_out_dir}/${windows_system}"
60  ndk_darwin_specific_out_dir = "${ndk_os_specific_out_dir}/${darwin_system}"
61  ndk_linux_specific_out_dir = "${ndk_os_specific_out_dir}/${linux_system}"
62  ndk_ohos_specific_out_dir = "${ndk_os_specific_out_dir}/${ohos_system}"
63}
64
65ndk_windows_toolchains_out_dir = "${ndk_windows_specific_out_dir}/llvm"
66ndk_windows_tools_out_dir = "${ndk_windows_specific_out_dir}/build-tools"
67
68ndk_darwin_toolchains_out_dir = "${ndk_darwin_specific_out_dir}/llvm"
69ndk_darwin_tools_out_dir = "${ndk_darwin_specific_out_dir}/build-tools"
70
71ndk_linux_toolchains_out_dir = "${ndk_linux_specific_out_dir}/llvm"
72ndk_linux_tools_out_dir = "${ndk_linux_specific_out_dir}/build-tools"
73
74ndk_ohos_toolchains_out_dir = "${ndk_ohos_specific_out_dir}/llvm"
75ndk_ohos_tools_out_dir = "${ndk_ohos_specific_out_dir}/build-tools"
76
77# Generate NDK library from NDK description file.
78#
79# Variables:
80#  ndk_description_file:
81#  min_compact_version: string specifies the minimal compactible version of NDK.
82#    set to major_version in default.
83#
84template("ohos_ndk_library") {
85  forward_variables_from(invoker, [ "testonly" ])
86  assert(defined(invoker.ndk_description_file),
87         "ndk description file is necessary ")
88
89  _ndk_description_file = invoker.ndk_description_file
90
91  _system_capability = ""
92  if (defined(invoker.system_capability)) {
93    _system_capability = invoker.system_capability
94  }
95
96  _system_capability_headers = ""
97  if (defined(invoker.system_capability_headers)) {
98    _system_capability_headers = invoker.system_capability_headers
99  }
100
101  _deps = []
102  if (defined(invoker.deps)) {
103    _deps += invoker.deps
104  }
105
106  _ndk_config_output = "$target_gen_dir/$target_name.build_config"
107  _sdk_version = exec_script("//build/ohos/version.py",
108                             [
109                               "--version",
110                               sdk_version,
111                             ],
112                             "list lines")
113  _min_compact_version = _sdk_version[0]
114  if (defined(invoker.min_compact_version)) {
115    _min_compact_version = invoker.min_compact_version
116  }
117  assert(_min_compact_version != "0")  # mark as used
118
119  _output_name = target_name
120  if (defined(invoker.output_name)) {
121    _output_name = invoker.output_name
122  }
123
124  _output_extension = "z.so"
125  if (defined(invoker.output_extension)) {
126    _output_extension = invoker.output_extension
127  }
128
129  _ndk_stub_target = "${target_name}__ndk_stub"
130  _generated_ndk_stub_file = target_gen_dir + "/${target_name}.ndk/" +
131                             get_path_info(_ndk_description_file, "name") + ".c"
132  _current_label = get_label_info(":${target_name}", "label_with_toolchain")
133  action_with_pydeps(_ndk_stub_target) {
134    deps = _deps
135    script = "//build/ohos/ndk/generate_ndk_stub_file.py"
136    depfile = "${target_gen_dir}/${target_name}.d"
137    args = [
138      "--output",
139      rebase_path(_generated_ndk_stub_file, root_build_dir),
140      "--ndk-description-file",
141      rebase_path(_ndk_description_file, root_build_dir),
142      "--depfile",
143      rebase_path(depfile, root_build_dir),
144    ]
145    inputs = [ _ndk_description_file ]
146    outputs = [ _generated_ndk_stub_file ]
147
148    _ndk_config_info = {
149      label = _current_label
150      lib_name = _output_name
151      system_capability = _system_capability
152      system_capability_headers = _system_capability_headers
153    }
154    metadata = {
155      ndk_config = [ _ndk_config_info ]
156    }
157  }
158
159  _ndk_config_target = "${target_name}__ndk_config"
160  generated_file(_ndk_config_target) {
161    deps = [ ":$_ndk_stub_target" ]
162    output_conversion = "json"
163    outputs = [ _ndk_config_output ]
164
165    data_keys = [ "ndk_config" ]
166  }
167
168  ndk_toolchains = []
169  if (build_ohos_ndk || use_current_sdk) {
170    ndk_toolchains = [
171      "//build/toolchain/ohos:ohos_clang_arm",
172      "//build/toolchain/ohos:ohos_clang_arm64",
173      "//build/toolchain/ohos:ohos_clang_x86_64",
174    ]
175  } else if (!is_arkui_x) {
176    # Don't enable cross compile if build_ohos_ndk is false.
177    # Cross compiling in this case may cause build failure in some scenario,
178    # such as build for ASAN.
179    ndk_toolchains = [ "//build/toolchain/ohos:ohos_clang_${target_cpu}" ]
180  }
181
182  if (ndk_toolchains == []) {
183    not_needed([ "_output_extension" ])
184  }
185
186  _accumulated_deps = []
187
188  foreach(_toolchain, ndk_toolchains) {
189    if (_toolchain == "//build/toolchain/ohos:ohos_clang_arm") {
190      _ndk_shlib_directory = "arm-linux-ohos"
191    } else if (_toolchain == "//build/toolchain/ohos:ohos_clang_arm64") {
192      _ndk_shlib_directory = "aarch64-linux-ohos"
193    } else if (_toolchain == "//build/toolchain/ohos:ohos_clang_x86_64") {
194      _ndk_shlib_directory = "x86_64-linux-ohos"
195    }
196
197    assert(defined(_ndk_shlib_directory))
198    _output_dir = "$ndk_libraries_out_dir/$_ndk_shlib_directory"
199    if (defined(invoker.current_ndk_outpath) &&
200        invoker.current_ndk_outpath != "" && use_current_sdk) {
201      _output_dir = "${invoker.current_ndk_outpath}/${_ndk_shlib_directory}"
202    }
203    _output_ndk_shlib = "${_output_dir}/lib${_output_name}.${_output_extension}"
204
205    _toolchain_name = get_label_info(_toolchain, "name")
206
207    _ndk_shlib_target = "${target_name}_${_toolchain_name}__ndk_shlib"
208
209    shared_library(_ndk_shlib_target) {
210      forward_variables_from(invoker,
211                             [
212                               "cflags",
213                               "ldflags",
214                               "configs",
215                               "libs",
216                               "include_dirs",
217                             ])
218      deps = [ ":$_ndk_stub_target" ]
219      sources = [ _generated_ndk_stub_file ]
220      output_dir = target_out_dir + "/$_toolchain_name"
221      output_name = _output_name
222      output_extension = _output_extension
223    }
224
225    _ndk_shlib_copy_target = "${target_name}_${_toolchain_name}__copy"
226    copy(_ndk_shlib_copy_target) {
227      deps = [ ":$_ndk_shlib_target($_toolchain)" ]
228      sources = [ get_label_info(":$_ndk_shlib_target($_toolchain)",
229                                 "target_out_dir") +
230                  "/$_toolchain_name/lib$_output_name.$_output_extension" ]
231      outputs = [ _output_ndk_shlib ]
232    }
233    _accumulated_deps += [ ":$_ndk_shlib_copy_target" ]
234    _accumulated_deps += [ ":$_ndk_shlib_target" ]
235  }
236
237  _ndk_version_script_target = target_name
238  if (current_toolchain == default_toolchain) {
239    # Notice file for different toolchains are the same, it's enough to
240    # collect notice file for default toolchain.
241    _notice_target = "${target_name}__ndk_libraries_notice"
242    collect_notice(_notice_target) {
243      forward_variables_from(invoker,
244                             [
245                               "testonly",
246                               "license_as_sources",
247                               "license_file",
248                             ])
249      module_source_dir =
250          get_label_info(":${_ndk_version_script_target}", "dir")
251      outputs = [ "$ndk_notice_dir/sysroot/usr/lib/lib$_output_name.$_output_extension.txt" ]
252    }
253    _accumulated_deps += [ ":$_notice_target" ]
254  }
255  if (defined(invoker.license_file)) {
256    not_needed(invoker, [ "license_file" ])
257  }
258  if (defined(invoker.license_as_sources)) {
259    not_needed(invoker, [ "license_as_sources" ])
260  }
261
262  _generated_version_script =
263      target_gen_dir + "/$target_name" + version_script_suffix
264  action_with_pydeps(_ndk_version_script_target) {
265    deps = _accumulated_deps
266    script = "//build/ohos/ndk/generate_version_script.py"
267    depfile = "${target_gen_dir}/${target_name}.d"
268    args = [
269      "--output",
270      rebase_path(_generated_version_script, root_build_dir),
271      "--ndk-description-file",
272      rebase_path(_ndk_description_file, root_build_dir),
273      "--shlib-name",
274      _output_name,
275      "--depfile",
276      rebase_path(depfile, root_build_dir),
277    ]
278    outputs = [ _generated_version_script ]
279  }
280}
281
282# Specify an ndk copy target
283# NOTE: It's an internal template, not designed for everyone use.
284#
285# Input variables:
286#   dest_dir: Root directory where sources are copied to.
287#   sources: List of files and directories to copy to ${dest_dir}.
288#
289template("ohos_ndk_copy") {
290  assert(defined(invoker.sources) && defined(invoker.dest_dir),
291         "sources and dest_dir are necessary ")
292
293  _deps = []
294  if (defined(invoker.deps)) {
295    _deps += invoker.deps
296  }
297  _dest = invoker.dest_dir
298
299  if (defined(invoker.current_ndk_outpath) &&
300      invoker.current_ndk_outpath != "" && use_current_sdk) {
301    _dest = invoker.current_ndk_outpath
302  }
303
304  sources = filter_exclude([ _dest ], [ "*os-irrelevant*" ])
305  if (sources == []) {
306    _notice_rel_dir = ndk_os_irrelevant_out_dir
307  } else {
308    _notice_rel_dir = ndk_os_specific_out_dir
309  }
310  sources = []
311
312  _main_target_name = target_name
313  _notice_target = "${target_name}__notice"
314  collect_notice(_notice_target) {
315    forward_variables_from(invoker,
316                           [
317                             "testonly",
318                             "license_as_sources",
319                             "license_file",
320                           ])
321    module_source_dir = get_label_info(":${_main_target_name}", "dir")
322    outputs = []
323
324    foreach(s, invoker.sources) {
325      outputs += [ ndk_notice_dir + "/" + rebase_path(_dest, _notice_rel_dir) +
326                   "/" + get_path_info(s, "file") + ".txt" ]
327    }
328  }
329  _deps += [ ":$_notice_target" ]
330  _clear_dest = true
331  if (defined(invoker.clear_dest) && !invoker.clear_dest) {
332    _clear_dest = false
333  }
334
335  copy_ex(target_name) {
336    forward_variables_from(invoker,
337                           [
338                             "testonly",
339                             "visibility",
340                           ])
341    forward_variables_from(invoker, [ "outputs" ])
342    deps = _deps
343    sources = invoker.sources
344
345    if (!defined(outputs)) {
346      outputs = []
347      foreach(src, invoker.sources) {
348        _all_files = []
349        _all_files =
350            exec_script("//build/scripts/find.py",
351                        [
352                          rebase_path(src, root_build_dir),
353                          "--base-dir=" + rebase_path(src, root_build_dir),
354                          "--return-relpath",
355                          "--follow-symlinks",
356                        ],
357                        "list lines")
358
359        if (_all_files == [ "." ]) {
360          outputs += [ _dest + "/" + get_path_info(src, "file") ]
361        } else {
362          foreach(f, _all_files) {
363            outputs += [ _dest + "/" + get_path_info(src, "name") + "/$f" ]
364          }
365        }
366      }
367    }
368
369    dest = _dest
370    depfile = "$target_gen_dir/$target_name.d"
371    args = [
372      "--clear",
373      "--follow-outside-symlinks",
374      "--depfile",
375      rebase_path(depfile, root_build_dir),
376      "--stamp",
377      rebase_path("$target_gen_dir/$target_name.stamp", root_build_dir),
378    ]
379    if (!_clear_dest) {
380      args -= [ "--clear" ]
381    }
382    if (defined(invoker.args)) {
383      args += invoker.args
384    }
385  }
386}
387
388# Specify ndk header files
389#
390# Input variables:
391#   dest_dir: Root directory where sources are copied to.
392#   sources: List of files and directories to copy to ${dest_dir}.
393#
394template("ohos_ndk_headers") {
395  assert(defined(invoker.sources), "sources are necessary ")
396
397  if (defined(invoker.dest_dir)) {
398    _dest_dir = invoker.dest_dir
399  } else {
400    _dest_dir = "$ndk_headers_out_dir"
401  }
402
403  if (defined(invoker.current_ndk_outpath) &&
404      invoker.current_ndk_outpath != "" && use_current_sdk) {
405    _dest_dir = invoker.current_ndk_outpath
406  }
407
408  _ndk_header_signature_target = "${target_name}__ndk_signature_check"
409  _target_name = target_name
410  action_with_pydeps(_ndk_header_signature_target) {
411    if (defined(invoker.deps)) {
412      deps = invoker.deps
413    }
414
415    script = "//build/ohos/ndk/check_ndk_header_signature.py"
416    depfile = "${target_gen_dir}/${target_name}.d"
417
418    inputs = []
419    foreach(src, invoker.sources) {
420      _all_files = []
421      _all_files = exec_script("//build/scripts/find.py",
422                               [ rebase_path(src) ],
423                               "list lines")
424
425      inputs += _all_files
426    }
427
428    _output = "$target_gen_dir/$target_name.stamp"
429
430    args = [
431      "--depfile",
432      rebase_path(depfile, root_build_dir),
433      "--generated-signature",
434      rebase_path("$ndk_signature_out_dir/$_target_name/signature.txt",
435                  root_build_dir),
436      "--saved-signature",
437      rebase_path("$ndk_signature_save_dir/$_target_name/signature.txt",
438                  root_build_dir),
439      "--output",
440      rebase_path(_output, root_build_dir),
441    ]
442    foreach(f, inputs) {
443      args += [
444        "--headers",
445        rebase_path(f, root_build_dir),
446        "--root-build-dir",
447        rebase_path("//", root_build_dir),
448      ]
449    }
450
451    if (check_ndk_signature) {
452      args += [ "--check-signature" ]
453    }
454
455    outputs = [ _output ]
456  }
457
458  _ndk_header_check_target = "${target_name}__ndk_header_check"
459  action_with_pydeps(_ndk_header_check_target) {
460    script = "//build/ohos/ndk/check_ndk_header.py"
461    inputs = []
462    foreach(src, invoker.sources) {
463      _all_files = []
464      _all_files = exec_script("//build/scripts/find.py",
465                               [ rebase_path(src) ],
466                               "list lines")
467
468      inputs += _all_files
469    }
470
471    _output = "$target_gen_dir/$target_name.gch"
472    args = [
473      "--output",
474      rebase_path(_output, root_build_dir),
475    ]
476    foreach(f, inputs) {
477      args += [
478        "--headers",
479        rebase_path(f, root_build_dir),
480      ]
481    }
482
483    outputs = [ _output ]
484  }
485  ohos_ndk_copy(target_name) {
486    forward_variables_from(invoker,
487                           "*",
488                           [
489                             "deps",
490                             "args",
491                             "dest_dir",
492                           ])
493    deps = [ ":$_ndk_header_signature_target" ]
494    if (defined(ndk_check_header) && target_name != "libuv_uv_header") {
495      deps += [ ":$_ndk_header_check_target" ]
496    }
497
498    if (defined(invoker.deps)) {
499      deps += invoker.deps
500    }
501    dest_dir = _dest_dir
502
503    args = [ "--ignore-stale" ]
504    if (defined(invoker.args)) {
505      args += invoker.args
506    }
507  }
508}
509
510# Specify ndk toolchains
511#
512# Input variables:
513#   dest_dir: Root directory where sources are copied to.
514#   sources: List of files and directories to copy to ${dest_dir}.
515#
516template("ohos_ndk_toolchains") {
517  ohos_ndk_copy(target_name) {
518    forward_variables_from(invoker, "*")
519  }
520}
521
522# Specify ndk prebuilt library
523#
524# Input variables:
525#   dest_dir: Root directory where sources are copied to.
526#   sources: List of files and directories to copy to ${dest_dir}.
527#
528template("ohos_ndk_prebuilt_library") {
529  if (defined(invoker.dest_dir)) {
530    _dest_dir = invoker.dest_dir
531  } else {
532    _dest_dir = "$ndk_libraries_out_dir"
533  }
534
535  if (defined(invoker.current_ndk_outpath) &&
536      invoker.current_ndk_outpath != "" && use_current_sdk) {
537    _dest_dir = invoker.current_ndk_outpath
538  }
539
540  ohos_ndk_copy(target_name) {
541    forward_variables_from(invoker,
542                           "*",
543                           [
544                             "args",
545                             "dest_dir",
546                           ])
547    dest_dir = _dest_dir
548
549    args = [ "--ignore-stale" ]
550    if (defined(invoker.args)) {
551      args += invoker.args
552    }
553  }
554}
555
556template("current_ndk") {
557  forward_variables_from(invoker,
558                         [
559                           "ndk_class",
560                           "all_ndk_targets",
561                           "ndk_out_dir",
562                         ])
563
564  package_info_name = "oh-uni-package"
565  if (ndk_class != "base") {
566    package_info_name = "uni-package"
567  }
568  package_info_file = "$ndk_out_dir/$package_info_name.json"
569
570  package_info = {
571    path = "native"
572    displayName = "Native"
573    version = current_ndk_version
574    if (release_type != "") {
575      releaseType = release_type
576    }
577    if (meta_version != "") {
578      meta = {
579        metaVersion = meta_version
580      }
581    }
582    if (defined(ext_ndk_config_file) && ext_ndk_config_file != "") {
583      platformVersion = platform_version
584    }
585    apiVersion = api_version
586  }
587  write_file(package_info_file, package_info, "json")
588
589  action_with_pydeps(target_name) {
590    deps = all_ndk_targets
591    script = "//build/ohos/ndk/collect_ndk_syscap.py"
592    depfile = "$target_gen_dir/$target_name.d"
593    _ndk_syscap_desc_file = "${ndk_out_dir}/ndk_system_capability.json"
594    _native_syscap_config_file = "${ndk_out_dir}/nativeapi_syscap_config.json"
595    outputs = [ _ndk_syscap_desc_file ]
596    args = [
597      "--depfile",
598      rebase_path(depfile, root_build_dir),
599      "--system-capability-file",
600      rebase_path(_ndk_syscap_desc_file, root_build_dir),
601      "--system-capability-header-config",
602      rebase_path(_native_syscap_config_file, root_build_dir),
603      "--targets-build-config",
604    ]
605    foreach(_ndk_target, all_ndk_targets) {
606      _target_bc_file = get_label_info(_ndk_target, "target_gen_dir") + "/" +
607                        get_label_info(_ndk_target, "name") + ".build_config"
608      args += [ rebase_path(_target_bc_file, root_build_dir) ]
609    }
610  }
611}
612