blob: dd1cec2cc5f6c1d07d28e94cbbe775640b2aa074 [file] [log] [blame]
# Copyright 2023 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("config.gni")
# Generates an include file that includes all needed third_party/icu
# headers, and presents them as a build target.
#
# To use, do the following:
#
# - In your BUILD file:
#
# import("//build/icu/third_party_icu_headers.gni")
#
# third_party_icu_headers("some_headers") {
# headers = [
# "third_party/icu/foo/bar/baz.h",
# ]
# }
#
# source_set("your_library") {
# # ...
# deps = [ ":some_headers" ]
# # ...
# }
#
# - In your source file:
#
# #include "your/source/file/directory/some_headers.h"
#
# This will produce a file `some_headers.h` in
#
# "${target_gen_dir}/your/source/file/directory/some_headers.h"
#
# which consists of only includes of the named headers, but with the initial
# "third_party/icu" substituted with the content of `$icu_root`. If
# the value was set to `icu_root = "//other_dir/icu", the resulting file
# content would be:
#
# #include "other_dir/icu/foo/bar/baz.h"
#
# for each header listed in the `headers` parameter.
#
# This allows us to place the library `//third_party/icu` into a different
# directory, in a way that is transparent to the library users, so long as
# the headers are declared using `third_party_icu_headers`.
#
# We use this approach because we must vary the path to the ICU library to
# account for issues in our build process for some products. The key variable
# is $icu_root, which determines where the build system will look for the ICU
# library. However, since the header files are also included in our source
# files, and their names vary with the choice of the ICU library location, we
# must fix up those include paths as well. Since there is no elegant way to do
# this in source directly, we generate the appropriate headers and include
# those.
#
# Args:
#
# headers: list(target): a list of headers from "third_party/icu" that you
# need to include.
#
# icu_assembly: bool: if set, builds ICU assembly flavors of this target.
# This is useful for a gradual rollout of flavored builds.
template("third_party_icu_headers") {
forward_variables_from(invoker,
[
"headers",
"icu_assembly",
])
icu_target_name = target_name
_header_name = "${target_gen_dir}/${icu_target_name}.h"
icu_assembly = false
if (defined(invoker.icu_assembly)) {
icu_assembly = invoker.icu_assembly
}
# Separate source targets, one for each ICU flavor supported. All built from
# the same file, which has different FUCHSIA_ICU_VARIANT env variables defined.
if (icu_assembly) {
foreach(icu_flavor, icu_flavors) {
source_set(
"${icu_target_name}.icu_${icu_flavor.name}_${icu_flavor.commit_id}") {
# gn check is wrong about includes here. Don't check.
# See the same declaration at the very bottom of this file for the
# reason.
check_includes = false
sources = [ _header_name ]
public_deps = [ "//third_party/icu/${icu_flavor.name}:icu" ]
public_configs = [
# defines FUCHSIA_ICU_VARIANT
"//src/lib/icu:${icu_flavor.name}",
]
}
}
}
# Writes out the header file contents during the analysis phase.
_contents = []
# "//third_party/icu" --> "third_party/icu"
_icu_dir = string_replace(icu_root, "//", "", 1)
if (icu_assembly) {
_icu_dirs = {
default = "third_party/icu/default"
latest = "third_party/icu/latest"
}
}
_contents_map = {
default = []
latest = []
}
foreach(_header, headers) {
# #include "third_party/icu/blah" --> #include "${icu_root}/blah"
_fixed_header_path = string_replace(_header, "third_party/icu", _icu_dir, 1)
_contents += [ "#include \"${_fixed_header_path}\"" ]
if (icu_assembly) {
# Same as above, but for flavors.
_header_path = {
}
_header_path = {
default =
string_replace(_header, "third_party/icu", _icu_dirs.default, 1)
latest = string_replace(_header, "third_party/icu", _icu_dirs.latest, 1)
}
_contents_map.default += [ "#include \"${_header_path.default}\"" ]
_contents_map.latest += [ "#include \"${_header_path.latest}\"" ]
}
}
_all_contents =
[
"/* Autogenerated by //build/icu/third_party_icu_headers. */",
"#ifndef FUCHSIA_ICU_VARIANT /* For non-varianted builds. */",
] + _contents +
[ "#elif FUCHSIA_ICU_VARIANT == 0 /* //src/lib/icu:default */" ] +
_contents_map.default +
[ "#elif FUCHSIA_ICU_VARIANT == 2 /* //src/lib/icu:latest */" ] +
_contents_map.latest +
[ "#elif FUCHSIA_ICU_VARIANT == 3 /* //src/lib/icu:icu_root */" ] +
_contents +
[
"#else",
"/* Refer to //src/lib/icu:{default,latest,icu_root} */",
"# error FUCHSIA_ICU_VARIANT needs a value between 0 and 3",
"#endif",
]
write_file(_header_name, _all_contents, "list lines")
source_set("${icu_target_name}") {
# gn check is wrong about includes here. Don't check.
#
# gn check does not seem to take the preprocessor results when checking
# for inclusion. The generated file here has several mutually exclusive
# ifdefs, each including its appropriate public_deps. Each such ifdef
# branch has its includes and deps set correctly, but gn does not know
# that and objects about missing deps for includes that are effectively
# ifdef'd out.
check_includes = false
sources = [ _header_name ]
public_deps = [
"//src/lib/icu:data",
"//src/lib/icu:lib",
]
public_configs = [
"${icu_root}:icu_config",
# defines FUCHSIA_ICU_VARIANT
"//src/lib/icu:icu_root",
]
}
}