| # Copyright 2016 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("//build/dart/config.gni") |
| |
| declare_args() { |
| # Debug build. |
| is_debug = true |
| } |
| |
| if (target_os == "") { |
| target_os = "fuchsia" |
| } |
| if (target_cpu == "") { |
| target_cpu = host_cpu |
| } |
| if (current_cpu == "") { |
| current_cpu = target_cpu |
| } |
| if (current_os == "") { |
| current_os = target_os |
| } |
| host_platform = "${host_os}-${host_cpu}" |
| |
| if (target_os == "fuchsia") { |
| target_toolchain = "//build/toolchain/fuchsia:${target_cpu}" |
| } else { |
| assert(false, "Target OS not supported") |
| } |
| |
| if (host_os == "linux" || host_os == "mac") { |
| host_toolchain = "//build/toolchain:host_${host_cpu}" |
| } else { |
| assert(false, "Host OS not supported") |
| } |
| |
| set_default_toolchain(target_toolchain) |
| |
| # Some projects expect a default value for sources_assignment_filter. |
| sources_assignment_filter = [] |
| |
| declare_args() { |
| # This should never be set as a build argument. It exists only to be |
| # set in toolchain_args when defining a toolchain. These configs |
| # will be appended to the default list common to all target types. |
| toolchain_configs = [] |
| |
| # This should never be set as a build argument. |
| # It exists only to be set in toolchain_args. |
| # See //build/toolchain/clang_toolchain.gni for details. |
| is_pic_default = false |
| |
| # This should never be set as a build argument. |
| # It exists only to be set in toolchain_args. |
| # See //build/toolchain/clang_toolchain.gni for details. |
| toolchain_variant = [] |
| |
| # This should never be set as a build argument. |
| # It exists only to be set in toolchain_args. |
| # See //build/toolchain/clang_toolchain.gni for details. |
| current_base_toolchain = target_toolchain |
| |
| # Zircon projects to target - must match the target architecture. |
| zircon_projects = [] |
| |
| # DEPRECATED: zircon build project |
| # Use zircon_projects instead |
| zircon_project = "" |
| } |
| |
| if (zircon_project != "") { |
| assert(zircon_projects == [], "Use zircon_projects instead of zircon_project") |
| zircon_projects = [ zircon_project ] |
| } else if (zircon_projects == []) { |
| if (current_cpu == "arm64") { |
| zircon_projects = [ "zircon-qemu-arm64" ] |
| } else if (current_cpu == "x64") { |
| zircon_projects = [ "zircon-pc-x86-64" ] |
| } |
| } |
| if (target_cpu == "x64") { |
| zircon_sysroot = |
| rebase_path("//out/build-zircon/build-zircon-pc-x86-64/sysroot") |
| } else { |
| assert(target_cpu == "arm64", "Unsupported target architecture $target_cpu") |
| zircon_sysroot = |
| rebase_path("//out/build-zircon/build-zircon-qemu-arm64/sysroot") |
| } |
| |
| is_android = false |
| is_fuchsia = false |
| is_fuchsia_host = false |
| is_ios = false |
| is_linux = false |
| is_mac = false |
| is_win = false |
| is_clang = true |
| is_component_build = false |
| is_official_build = false |
| |
| if (current_os == "fuchsia") { |
| is_fuchsia = true |
| } else if (current_os == "linux") { |
| is_linux = true |
| is_fuchsia_host = true |
| } else if (current_os == "mac") { |
| is_mac = true |
| is_fuchsia_host = true |
| } |
| |
| # Each variant toolchain's name is formed by taking the base toolchain |
| # name and successively appending "-$name" for each config listed in |
| # the variant, where name is `get_label_name(config, "name")`. |
| # NOTE: This must match the method used in |
| # //build/toolchain/clang_toolchain.gni:clang_toolchain_suite |
| current_toolchain_variant = "" |
| foreach(subvariant, toolchain_variant) { |
| current_toolchain_variant += "-" + get_label_info(subvariant, "name") |
| } |
| |
| # When we are in a variant of host_toolchain, change the value of |
| # host_toolchain so that `if (current_toolchain == host_toolchain)` |
| # tests still match, since that is the conventional way to detect being |
| # in host context. This means that any "...($host_toolchain)" label |
| # references from inside a variant of host_toolchain will refer to the |
| # variant (current_toolchain rather than host_toolchain). To handle |
| # this, the executable() template below will define its target in other |
| # variant toolchains as a copy of the real executable. |
| if (is_fuchsia_host) { |
| host_toolchain += current_toolchain_variant |
| } |
| |
| # References should use "label($shlib_toolchain)" rather than |
| # "label(${target_toolchain}-shared)" or anything else. |
| shlib_toolchain = "${current_base_toolchain}${current_toolchain_variant}-shared" |
| |
| # All binary targets will get this list of configs by default. |
| default_common_binary_configs = [ |
| "//build/config:compiler", |
| "//build/config:relative_paths", |
| "//build/config:default_include_dirs", |
| "//build/config:default_warnings", |
| "//build/config:no_exceptions", |
| "//build/config:no_rtti", |
| "//build/config:symbol_visibility_hidden", |
| ] |
| |
| if (is_debug) { |
| default_common_binary_configs += [ "//build/config:debug" ] |
| } else { |
| default_common_binary_configs += [ "//build/config:release" ] |
| } |
| |
| if (is_fuchsia) { |
| default_common_binary_configs += [ |
| "//build/config/fuchsia:icf", |
| "//build/config/fuchsia:thread_safety_annotations", |
| "//build/config/fuchsia:werror", |
| |
| # TODO(mcgrathr): Perhaps restrict this to only affected code. |
| # For now, safest to do it everywhere. |
| "//build/config/fuchsia:zircon_asserts", |
| ] |
| |
| # Add safestack when not using a variant that's incompatible. |
| # TODO(mcgrathr): When -fsanitize=safe-stack is the default in the |
| # compiler, this will not be necessary: -fsanitize=address et al will |
| # implicitly disable safestack. |
| _safestack_compatible = true |
| foreach(subvariant, toolchain_variant) { |
| if (subvariant == "//build/config/sanitizers:asan" || |
| subvariant == "//build/config/sanitizers:asan_no_detect_leaks" || |
| subvariant == "//build/config/sanitizers:sancov") { |
| _safestack_compatible = false |
| } |
| } |
| if (_safestack_compatible) { |
| default_common_binary_configs += [ "//build/config/fuchsia:safestack" ] |
| } |
| } |
| |
| default_common_binary_configs += [ "//build/config/lto:default" ] |
| |
| # Add configs set by the toolchain definition. |
| default_common_binary_configs += toolchain_configs + toolchain_variant |
| |
| default_shared_library_configs = |
| default_common_binary_configs + [ "//build/config:shared_library_config" ] |
| |
| # On most systems, the sanitizer runtimes are normally linked statically |
| # and so -shared links do not include them. Using -shared --no-undefined |
| # with sanitized code will get undefined references for the sanitizer |
| # runtime calls generated by the compiler. Assuming that variants are |
| # likely sanitizers prone to this issue, avoid that config for variants. |
| # It shouldn't do much harm, since the non-variant builds will catch the |
| # real undefined reference bugs. |
| if (toolchain_variant == []) { |
| default_shared_library_configs += [ "//build/config:symbol_no_undefined" ] |
| } |
| |
| default_executable_configs = default_common_binary_configs + [ |
| "//build/config:executable_config", |
| "//build/config:default_libs", |
| ] |
| |
| if (is_pic_default) { |
| default_common_binary_configs += [ "//build/config:shared_library_config" ] |
| } |
| |
| # Apply that default list to the binary target types. |
| set_defaults("source_set") { |
| configs = default_common_binary_configs |
| } |
| set_defaults("static_library") { |
| configs = default_common_binary_configs |
| } |
| set_defaults("shared_library") { |
| configs = default_shared_library_configs |
| } |
| set_defaults("loadable_module") { |
| configs = default_shared_library_configs |
| } |
| set_defaults("executable") { |
| configs = default_executable_configs |
| } |
| |
| if (is_fuchsia) { |
| if (!is_pic_default) { |
| # In the main toolchain, shared_library just redirects to the same |
| # target in the -shared toolchain. |
| template("shared_library") { |
| group(target_name) { |
| # Mark all variables as not needed to suppress errors for unused |
| # variables. The other variables normally passed to shared_library |
| # are actually used by the shared_library instantiation in the |
| # -shared toolchain, so any going truly unused will be caught there. |
| not_needed(invoker, "*") |
| forward_variables_from(invoker, |
| [ |
| "data_deps", |
| "deps", |
| "public_deps", |
| "all_dependent_configs", |
| "public_configs", |
| "testonly", |
| "visibility", |
| ]) |
| |
| if (!defined(public_deps)) { |
| public_deps = [] |
| } |
| public_deps += [ ":$target_name(${current_toolchain}-shared)" ] |
| } |
| } |
| } else { |
| # In the -shared toolchain, shared_library is just its normal self, |
| # but if the invoker constrained the visibility, we must make sure |
| # the dependency from the main toolchain is still allowed. |
| template("shared_library") { |
| shared_library(target_name) { |
| # Explicitly forward visibility, implicitly forward everything |
| # else. Forwarding "*" doesn't recurse into nested scopes (to |
| # avoid copying all globals into each template invocation), so |
| # won't pick up file-scoped variables. Normally this isn't too |
| # bad, but visibility is commonly defined at the file scope. |
| # Explicitly forwarding visibility and then excluding it from the |
| # "*" set works around this problem. See http://crbug.com/594610 |
| # for rationale on why this GN behavior is not considered a bug. |
| forward_variables_from(invoker, [ "visibility" ]) |
| forward_variables_from(invoker, "*", [ "visibility" ]) |
| if (defined(visibility)) { |
| visibility += [ ":$target_name" ] |
| } |
| } |
| } |
| } |
| } |
| |
| declare_args() { |
| # List of "selectors" to request variant builds of certain targets. |
| # Each selector specifies matching criteria and a chosen variant. |
| # The first selector in the list to match a given target determines |
| # which variant is used for that target. Each selector is a scope, |
| # defining some of these: |
| # |
| # variant |
| # Required: The variant that applies if this selector matches. |
| # This can be false to choose no variant, or a string that names |
| # the variant. Variant names are composed of the names of configs |
| # that make up the variant, separated by "-" if there is more than |
| # one config. `known_variants + extra_variants` is the set of |
| # available variants; see those build arguments. |
| # |
| # The rest below are matching criteria. |
| # The selector matches if and only if all of its criteria match. |
| # If none of these is defined, then the selector always matches. |
| # Each "Strings" criterion is a list of strings, and the criterion |
| # is satisfied if any of the strings match against the candidate string. |
| # |
| # host |
| # Boolean: If true, the selector matches in the host toolchain. |
| # If false, the selector matches in the target toolchain. |
| # |
| # testonly |
| # Boolean: If true, the selector matches targets with testonly=true. |
| # If false, the selector matches in targets without testonly=true. |
| # |
| # target_type |
| # Strings: Matches "executable", "loadable_module", or "driver_module" |
| # |
| # output_name |
| # Strings: Matches the target's `output_name` (default: its target name). |
| # |
| # label |
| # Strings: Matches the target's full label (without toolchain). |
| # |
| # name |
| # Strings: Matches the target's simple name (label after last / or :). |
| # |
| # dir |
| # Strings: Matches target's label directory. |
| select_variant = [] |
| } |
| |
| template("variant_target") { |
| target_type = target_name |
| target_name = invoker.target_name |
| target_invoker = { |
| # Explicitly forward visibility, implicitly forward everything else. |
| # See comment in template("shared_library") above for details. |
| forward_variables_from(invoker, [ "visibility" ]) |
| forward_variables_from(invoker, |
| "*", |
| [ |
| "_target_type", |
| "target_name", |
| "visibility", |
| ]) |
| |
| if (!defined(output_name)) { |
| output_name = target_name |
| } |
| } |
| |
| # target_type is the real GN target type that builds the thing. |
| # selector_target_type is the name matched against target_type selectors. |
| if (defined(invoker._target_type)) { |
| selector_target_type = invoker._target_type |
| } else { |
| selector_target_type = target_type |
| } |
| |
| target_label = get_label_info(":$target_name", "label_no_toolchain") |
| |
| # These are not actually used in all possible if branches below, |
| # so defang GN's extremely sensitive "unused variable" errors. |
| not_needed([ |
| "selector_target_type", |
| "target_invoker", |
| "target_label", |
| "target_type", |
| ]) |
| |
| target_variant = false |
| if (select_variant != []) { |
| # See if there is a selector that matches this target. |
| selected = false |
| foreach(selector, select_variant) { |
| # The first match wins. |
| # GN's loops don't have "break", so do nothing on later iterations. |
| if (!selected) { |
| # Expand the selector so we don't have to do a lot of defined(...) |
| # tests below. |
| select = { |
| } |
| select = { |
| target_type = [] |
| output_name = [] |
| label = [] |
| name = [] |
| dir = [] |
| forward_variables_from(selector, "*") |
| } |
| |
| selected = true |
| if (selected && defined(selector.host)) { |
| selected = is_fuchsia_host == selector.host |
| } |
| |
| if (selected && defined(selector.testonly)) { |
| selected = (defined(target_invoker.testonly) && |
| target_invoker.testonly) == selector.testonly |
| } |
| |
| if (selected && select.target_type != []) { |
| selected = false |
| candidate = selector_target_type |
| foreach(try, select.target_type) { |
| if (try == candidate) { |
| selected = true |
| } |
| } |
| } |
| |
| if (selected && select.output_name != []) { |
| selected = false |
| candidate = target_invoker.output_name |
| foreach(try, select.output_name) { |
| if (try == candidate) { |
| selected = true |
| } |
| } |
| } |
| |
| if (selected && select.label != []) { |
| selected = false |
| candidate = target_label |
| foreach(try, select.label) { |
| if (try == candidate) { |
| selected = true |
| } |
| } |
| } |
| |
| if (selected && select.name != []) { |
| selected = false |
| candidate = get_label_info(target_label, "name") |
| foreach(try, select.name) { |
| if (try == candidate) { |
| selected = true |
| } |
| } |
| } |
| |
| if (selected && select.dir != []) { |
| selected = false |
| candidate = get_label_info(target_label, "dir") |
| foreach(try, select.dir) { |
| if (try == candidate) { |
| selected = true |
| } |
| } |
| } |
| |
| if (selected && selector.variant != false) { |
| target_variant = "-${selector.variant}" |
| } |
| } |
| } |
| } |
| if (target_variant == false) { |
| target_variant = "" |
| } |
| |
| builder_toolchain = current_base_toolchain + target_variant |
| if (invoker._variant_shared) { |
| builder_toolchain += "-shared" |
| } |
| |
| if (current_toolchain == builder_toolchain) { |
| # This is the toolchain selected to actually build this target. |
| target(target_type, target_name) { |
| deps = [] |
| forward_variables_from(target_invoker, "*") |
| foreach(variant, toolchain_variant) { |
| # Expand the label so it always has a :name part. |
| variant = get_label_info(variant, "label_no_toolchain") |
| deps += [ "${variant}_deps" ] |
| } |
| if (defined(visibility)) { |
| # Other toolchains will define this target as a group or copy |
| # rule that depends on this toolchain's definition. If the |
| # invoker constrained the visibility, make sure those |
| # dependencies from other toolchains are still allowed. |
| visibility += [ ":${target_name}" ] |
| } |
| } |
| } else if (current_toolchain == shlib_toolchain) { |
| # Don't copy from a variant into a -shared toolchain, because nobody |
| # looks for an executable or loadable_module there. Instead, just |
| # forward any deps to the real target. |
| group(target_name) { |
| forward_variables_from(target_invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| if (defined(visibility)) { |
| visibility += [ ":${target_name}" ] |
| } |
| deps = [ |
| ":${target_name}(${builder_toolchain})", |
| ] |
| } |
| } else { |
| # When some variant was selected, then this target in all other |
| # toolchains is actually just this copy rule. The target is built in |
| # the selected variant toolchain, but then copied to its usual name in |
| # $root_out_dir so that things can find it there. |
| copy_vars = { |
| forward_variables_from(target_invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| if (defined(visibility)) { |
| visibility += [ ":${target_name}" ] |
| } |
| |
| deps = [ |
| ":${target_name}(${builder_toolchain})", |
| ] |
| variant_out_dir = get_label_info(deps[0], "root_out_dir") |
| |
| full_output_name = target_invoker.output_name |
| if (defined(target_invoker.output_extension) && |
| target_invoker.output_extension != "") { |
| full_output_name += ".${target_invoker.output_extension}" |
| } |
| |
| sources = [ |
| "$variant_out_dir/$full_output_name", |
| ] |
| outputs = [ |
| "$root_out_dir/$full_output_name", |
| ] |
| } |
| |
| # In the host toolchain, make a symlink rather than a hard link |
| # (which is what "copy" rules really do). Host tools are built with |
| # an embedded shared library lookup path based on $ORIGIN on Linux |
| # (//build/config/linux:compiler) and the equivalent @loader_path on |
| # macOS (//build/config/mac:mac_dynamic_flags). The dynamic linker |
| # translates this to "the directory containing the executable". |
| # With hard links, this gets the directory used to invoke the |
| # executable, which is host_toolchain's $root_out_dir. With |
| # symlinks, it instead gets the directory containing the actual |
| # executable file, which is builder_toolchain's $root_out_dir. |
| # Hence the program uses the variant builds of shared libraries that |
| # go with the variant build of the executable, rather using than the |
| # vanilla host_toolchain builds with the variant executable. |
| if (current_toolchain == host_toolchain) { |
| action(target_name) { |
| forward_variables_from(copy_vars, "*") |
| script = "/bin/ln" |
| args = [ |
| "-snf", |
| rebase_path(sources[0], root_out_dir), |
| rebase_path(outputs[0]), |
| ] |
| } |
| } else { |
| # For Fuchsia, //packages/gn/variant.py depends on hard links to |
| # identify the variants. |
| copy(target_name) { |
| forward_variables_from(copy_vars, "*") |
| } |
| } |
| } |
| } |
| |
| template("executable") { |
| _executable_name = target_name |
| _variant_shared = false |
| variant_target("executable") { |
| target_name = _executable_name |
| |
| # Explicitly forward visibility, implicitly forward everything else. |
| # See comment in template("shared_library") above for details. |
| forward_variables_from(invoker, [ "visibility" ]) |
| forward_variables_from(invoker, "*", [ "visibility" ]) |
| } |
| } |
| |
| template("loadable_module") { |
| _module_name = target_name |
| _variant_shared = true |
| variant_target("loadable_module") { |
| target_name = _module_name |
| if (defined(invoker._target_type)) { |
| _target_type = invoker._target_type |
| } |
| |
| # Explicitly forward visibility, implicitly forward everything else. |
| # See comment in template("shared_library") above for details. |
| forward_variables_from(invoker, [ "visibility" ]) |
| forward_variables_from(invoker, "*", [ "visibility" ]) |
| if (!defined(output_extension)) { |
| output_extension = "so" |
| } |
| } |
| } |
| |
| # Some targets we share with Chromium declare themselves to be components, |
| # which means they can build either as shared libraries or as static libraries. |
| # We build them as static libraries. |
| template("component") { |
| if (!defined(invoker.sources)) { |
| # When there are no sources defined, use a source set to avoid creating |
| # an empty static library (which generally don't work). |
| _component_mode = "source_set" |
| } else { |
| _component_mode = "static_library" |
| } |
| |
| target(_component_mode, target_name) { |
| # Explicitly forward visibility, implicitly forward everything else. |
| # See comment in template("shared_library") above for details. |
| forward_variables_from(invoker, [ "visibility" ]) |
| forward_variables_from(invoker, "*", [ "visibility" ]) |
| } |
| } |
| |
| set_defaults("component") { |
| configs = default_common_binary_configs |
| } |