| # Copyright 2017 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/config/clang/clang.gni") |
| import("//build/config/sysroot.gni") |
| import("//build/host.gni") |
| import("//build/sdk/sdk_host_tool.gni") |
| import("//build/toolchain/breakpad.gni") |
| import("//build/toolchain/concurrent_jobs.gni") |
| import("//zircon/public/sysroot/go.gni") |
| |
| declare_args() { |
| # gocache_dir |
| # Directory GOCACHE environment variable will be set to. This directory |
| # will have build and test results cached, and is safe to be written to |
| # concurrently. If overridden, this directory must be a full path. |
| gocache_dir = rebase_path("$root_out_dir/.gocache") |
| |
| # go_vet_enabled |
| # [bool] if false, go vet invocations are disabled for all builds. |
| go_vet_enabled = false |
| } |
| |
| # A template for an action that builds a Go binary. Users should instead use the |
| # go_binary or go_test rules. |
| # |
| # Parameters |
| # |
| # gopackages (required) |
| # List of packages to build. |
| # |
| # use_prebuilt_go (optional) |
| # If true, use a prebuilt go toolchain, rather than building the toolchain. |
| # If not set, defaults to false when targeting Fuchsia and true otherwise. |
| # |
| # sdk_category (optional) |
| # Publication level of the library in SDKs. |
| # See //build/sdk/sdk_atom.gni. |
| # |
| # sdk_name (optional) |
| # Name of the library in the SDK. |
| # |
| # deps (optional) |
| # List of labels representing go_library targets this target depends on. |
| # |
| # non_go_deps (optional) |
| # List of labels this target depends on that are not Go libraries. |
| # |
| # include_dirs (optional) |
| # List of directories this target depends on being in the C compiler include path. |
| # |
| # lib_dirs (optional) |
| # List of directories this target depends on being in the C compiler library path. |
| # |
| # skip_vet (optional) |
| # Whether to skip running go vet for this target. This flag should _only_ |
| # be used for packages in the Go source tree itself that otherwise match |
| # whitelist entries in go vet all. Go vet is only run if go_vet_enabled is |
| # true. |
| # |
| # test (optional, default: false) |
| # Whether this target defines a test. |
| # |
| # carchive (optional, default: false) |
| # Whether to build this target as a C archive. |
| # |
| # gcflags (optional) |
| # List of go compiler flags to pass. |
| # |
| # ldflags (optional) |
| # List of go linker flags to pass. |
| # |
| # tags (optional) |
| # List of go build tags to include in the build. |
| # |
| # cgo (optional, default: true) |
| # If true, will support linking against C code. Set to false for |
| # pure Go code to support cross-compilation. |
| # |
| # output_name (optional) |
| # The name of the binary that that will be generated. |
| # It defaults to the target name. |
| # |
| # output_dir (optional) |
| # Directory that the resulting binary should be placed in. |
| # See: `gn help output_dir` |
| # |
| template("go_build") { |
| assert(defined(invoker.gopackages), |
| "gopackages must be defined for $target_name") |
| gopackages = invoker.gopackages |
| assert( |
| gopackages == [ gopackages[0] ], |
| "gopackages currently only supports one package because of http://crbug.com/fuchsia/8088") |
| |
| main_target_name = target_name |
| is_test = defined(invoker.test) && invoker.test |
| carchive = defined(invoker.carchive) && invoker.carchive |
| assert(!(is_test && carchive), |
| "cannot specify both test=true and carchive=true") |
| |
| output_name = target_name |
| if (defined(invoker.output_name)) { |
| output_name = invoker.output_name |
| } |
| if (carchive) { |
| output_name = "${output_name}.a" |
| } |
| |
| if (defined(invoker.output_dir)) { |
| output_dir = invoker.output_dir |
| } else { |
| output_dir = root_out_dir |
| } |
| |
| define_sdk_target = defined(invoker.sdk_category) && |
| invoker.sdk_category != "excluded" && !is_test |
| |
| # Strip target binaries and binaries that are included in the SDK. |
| use_strip = (is_fuchsia || define_sdk_target) && !carchive |
| |
| output_path = "${output_dir}/${output_name}" |
| if (use_strip) { |
| output_path = "${output_dir}/exe.unstripped/${output_name}" |
| stripped_output_path = "${output_dir}/${output_name}" |
| } |
| |
| use_prebuilt_go = !is_fuchsia |
| if (defined(invoker.use_prebuilt_go)) { |
| use_prebuilt_go = invoker.use_prebuilt_go |
| } |
| goroot_deps = [] |
| if (use_prebuilt_go) { |
| goroot = rebase_path("//prebuilt/third_party/go/${host_platform}", |
| root_build_dir) |
| } else { |
| goroot = rebase_path("$host_tools_dir/goroot", root_build_dir) |
| goroot_deps = [ "//third_party/go:go_runtime" ] |
| } |
| |
| if (defined(invoker.deps)) { |
| go_deps_paths = [] |
| go_deps_inputs = [] |
| foreach(dep, invoker.deps) { |
| gen_dir = get_label_info(dep, "target_gen_dir") |
| name = get_label_info(dep, "name") |
| path = "${gen_dir}/${name}.go_deps" |
| go_deps_paths += [ rebase_path(path, root_build_dir) ] |
| go_deps_inputs += [ path ] |
| } |
| } |
| |
| hermetic_inputs_target_name = "${main_target_name}_hermetic_inputs" |
| hermetic_inputs_target_output = |
| "${target_gen_dir}/${output_name}.hermetic_inputs" |
| hermetic_inputs_action(hermetic_inputs_target_name) { |
| visibility = [ ":${main_target_name}" ] |
| forward_variables_from(invoker, [ "testonly" ]) |
| |
| script = "//build/go/gen_hermetic_inputs.py" |
| sources = [ "//build/go/gen_library_metadata.py" ] |
| outputs = [ hermetic_inputs_target_output ] |
| args = [ |
| "--output", |
| rebase_path(hermetic_inputs_target_output, root_build_dir), |
| "--go-root", |
| goroot, |
| ] |
| |
| deps = goroot_deps |
| if (defined(invoker.deps)) { |
| deps += invoker.deps |
| args += [ "--go-dep-files" ] |
| args += go_deps_paths |
| inputs = go_deps_inputs |
| } |
| |
| if (is_test) { |
| testonly = true |
| args += [ "--is-test=true" ] |
| } |
| } |
| |
| variant_target("action") { |
| target_name = main_target_name |
| _variant_shared = false |
| |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| forward_variables_from(concurrent_jobs.local, "*") |
| |
| deps = goroot_deps |
| if (defined(invoker.non_go_deps)) { |
| deps += invoker.non_go_deps |
| } |
| |
| if (use_strip) { |
| # Ensure that the 'canonical' output path of $root_out_dir/$output_name |
| # always first among outputs, as this path has to be reconstructed within |
| # go_test.gni and it can canonically compare that with outputs[0]. |
| outputs = [ |
| stripped_output_path, |
| output_path, |
| ] |
| } else { |
| outputs = [ output_path ] |
| } |
| |
| output_name = output_name |
| |
| # NOTE: output_dir is needed for variant_target(), but not for this action(). |
| output_dir = output_dir |
| not_needed([ "output_dir" ]) |
| |
| script = "//build/go/build.py" |
| sources = [ "//build/go/gen_library_metadata.py" ] |
| |
| hermetic_inputs_target = ":${hermetic_inputs_target_name}" |
| hermetic_inputs_file = hermetic_inputs_target_output |
| |
| if (is_fuchsia) { |
| # For Fuchsia binaries, use a Go-specific sysroot instead of the |
| # standard one which only contains empty linker stubs (see |
| # comments in //zircon/public/sysroot/BUILD.gn for details). |
| sysroot = go_sysroot_dir |
| } |
| |
| args = [ |
| "--root-out-dir", |
| rebase_path(root_out_dir, root_build_dir), |
| "--current-cpu", |
| current_cpu, |
| "--current-os", |
| current_os, |
| "--binname", |
| output_name, |
| "--output-path", |
| rebase_path(output_path, root_build_dir), |
| "--go-cache", |
| rebase_path(gocache_dir, root_build_dir), |
| "--go-root", |
| goroot, |
| "--cc", |
| "$rebased_clang_prefix/clang", |
| "--cxx", |
| "$rebased_clang_prefix/clang++", |
| "--objcopy", |
| "$rebased_clang_prefix/llvm-objcopy", |
| "--ar", |
| "$rebased_clang_prefix/llvm-ar", |
| "--sysroot", |
| rebase_path(sysroot, root_build_dir), |
| "--target", |
| current_target_tuple, |
| "--golibs-dir", |
| rebase_path("//third_party/golibs", root_build_dir), |
| ] |
| |
| include_dirs = [] |
| if (defined(invoker.include_dirs)) { |
| include_dirs = rebase_path(invoker.include_dirs, root_build_dir) |
| } |
| lib_dirs = [] |
| if (defined(invoker.lib_dirs)) { |
| lib_dirs = rebase_path(invoker.lib_dirs, root_build_dir) |
| } |
| lib_dirs += |
| [ rebase_path(get_label_info(":any($shlib_toolchain)", "root_out_dir"), |
| root_build_dir) ] |
| |
| if (!(defined(invoker.cgo) && !invoker.cgo)) { |
| args += [ "--cgo" ] |
| |
| if (is_fuchsia) { |
| # Inject a dependency to libfdio.so. Note that as a special case, |
| # when building fuzzing binaries, this library should be built in |
| # a non-fuzzing variant (because the fuzzing runtime depends on it). |
| # So compute the correct toolchain for it directly here. |
| _fdio_toolchain = |
| string_replace(current_toolchain, "-fuzzer", "") + "-shared" |
| _fdio_label_with_toolchain = "//sdk/lib/fdio($_fdio_toolchain)" |
| |
| deps += [ |
| "//zircon/public/sysroot:go_binary_deps", |
| _fdio_label_with_toolchain, |
| ] |
| |
| if (_fdio_toolchain != current_toolchain + "-shared") { |
| lib_dirs += [ rebase_path( |
| get_label_info(_fdio_label_with_toolchain, "root_out_dir"), |
| root_build_dir) ] |
| } |
| |
| include_dirs += |
| [ rebase_path("//sdk/lib/fdio/include", root_build_dir) ] |
| |
| # See //build/config/fuchsia:fdio_config. |
| lib_dirs += |
| [ rebase_path(get_label_info("//build/config/fuchsia:fdio_config", |
| "target_gen_dir"), |
| root_build_dir) ] |
| } |
| } |
| |
| foreach(include_dir, include_dirs) { |
| args += [ |
| "--include-dir", |
| include_dir, |
| ] |
| } |
| foreach(lib_dir, lib_dirs) { |
| args += [ |
| "--lib-dir", |
| lib_dir, |
| ] |
| } |
| |
| if (use_strip) { |
| args += [ |
| "--stripped-output-path", |
| rebase_path(stripped_output_path, root_build_dir), |
| ] |
| } |
| |
| if (defined(invoker.skip_vet) && !invoker.skip_vet && go_vet_enabled) { |
| args += [ "--vet" ] |
| } |
| |
| # Go build tags |
| if (defined(invoker.tags)) { |
| foreach(tag, invoker.tags) { |
| args += [ |
| "--tag", |
| tag, |
| ] |
| } |
| } |
| |
| # Go compiler flags |
| if (defined(invoker.gcflags)) { |
| foreach(gcflag, invoker.gcflags) { |
| args += [ "--gcflag=${gcflag}" ] |
| } |
| } |
| |
| if (is_fuchsia) { |
| # TODO(phosek): drop -Wl,--pack-dyn-relocs=relr once it's the default in Clang. |
| extldflags = "-Wl,--pack-dyn-relocs=relr" |
| |
| # TODO(fxbug.dev/53078): Eventually the default in the compler driver. |
| extldflags += ",-zrel" |
| |
| # When building with an instrumented variant, ensure the binary embeds a reference |
| # to the right dynamic linker path. |
| if (toolchain_variant.libprefix != "") { |
| extldflags += ",--dynamic-linker=${toolchain_variant.libprefix}ld.so.1" |
| } |
| args += [ "--ldflag=-linkmode=external \"-extldflags=$extldflags\"" ] |
| } |
| |
| if (defined(invoker.ldflags)) { |
| foreach(ldflag, invoker.ldflags) { |
| args += [ "--ldflag=${ldflag}" ] |
| } |
| } |
| |
| if (carchive) { |
| args += [ "--buildmode=c-archive" ] |
| |
| # carchive is only set when building go fuzzers as static libraries, |
| # that is then linked into a fuzzer executables. Make sure that it |
| # is built in the same build variant as the one used for these, to |
| # ensure they grab the right dependencies. |
| variant_selector_target_type = "fuzzed_executable" |
| } |
| |
| inputs = [] |
| if (is_fuchsia) { |
| if (!carchive && output_breakpad_syms && host_os != "mac") { |
| args += [ |
| "--dump-syms", |
| breakpad_dump_syms, |
| ] |
| inputs += [ breakpad_dump_syms_prebuilt ] |
| } |
| } |
| |
| if (!carchive) { |
| # Add needed arguments for the buildidtool. We should add the stamp file |
| # output by buildidtool to the list of outputs for this action but because |
| # Ninja (and by consequence GN) limits us to one depfile where that depfile |
| # has only one output and we need the depfile for other things we don't |
| # list it as an output. |
| args += [ |
| "--buildidtool", |
| rebase_path("//prebuilt/tools/buildidtool/${host_platform}/buildidtool", |
| root_build_dir), |
| "--build-id-dir", |
| ".build-id", |
| ] |
| } |
| |
| if (is_test) { |
| testonly = true |
| args += [ "--is-test=true" ] |
| } |
| |
| if (defined(invoker.deps)) { |
| deps += invoker.deps |
| args += [ "--go-dep-files" ] |
| args += go_deps_paths |
| inputs += go_deps_inputs |
| } |
| |
| foreach(gopackage, invoker.gopackages) { |
| args += [ |
| "--package", |
| gopackage, |
| ] |
| } |
| |
| metadata = { |
| tool_paths = [] |
| |
| # Record metadata for the //:tool_paths build API for all non-tests. |
| if (!is_test) { |
| tool_paths = [ |
| { |
| cpu = current_cpu |
| label = get_label_info(":$main_target_name", "label_with_toolchain") |
| name = output_name |
| os = current_os |
| path = rebase_path(output_path, root_build_dir) |
| }, |
| ] |
| } |
| |
| binaries = [ |
| { |
| type = "executable" |
| label = get_label_info(":$target_name", "label_with_toolchain") |
| cpu = current_cpu |
| os = current_os |
| debug = rebase_path(output_path, root_build_dir) |
| if (use_strip) { |
| dist = rebase_path(stripped_output_path, root_build_dir) |
| } else { |
| dist = debug |
| } |
| |
| # TODO(fxbug.dev/27215): Update when we add linux go binaries |
| # to .build-id. |
| if (is_fuchsia) { |
| elf_build_id = "$dist.build-id.stamp" |
| } |
| if (output_breakpad_syms && is_fuchsia) { |
| breakpad = "$dist.sym" |
| } |
| }, |
| ] |
| |
| # Used by the distribution_manifest template. |
| if (is_fuchsia) { |
| distribution_entries = [ |
| { |
| source = rebase_path(output_path, root_build_dir) |
| if (use_strip) { |
| source = rebase_path(stripped_output_path, root_build_dir) |
| } |
| destination = "bin/$output_name" |
| if (is_test) { |
| destination = "test/$output_name" |
| } |
| label = get_label_info(":$target_name", "label_with_toolchain") |
| elf_runtime_dir = "lib/${toolchain_variant.libprefix}" |
| }, |
| ] |
| |
| # Used by the fuchsia_test_component_manifest() template. |
| test_component_manifest_program = [ |
| { |
| program = { |
| binary = "bin/$output_name" |
| if (is_test) { |
| binary = "test/$output_name" |
| } |
| } |
| }, |
| ] |
| test_component_manifest_program_barrier = [] |
| |
| if (is_test) { |
| # Used by the fuchsia_test_component_manifest() template. |
| test_component_manifest_cml = [ |
| { |
| include = [ "//src/sys/test_runners/gotests/default.shard.cml" ] |
| }, |
| ] |
| } |
| } |
| } |
| if (output_breakpad_syms && is_fuchsia) { |
| metadata_binaries = metadata.binaries |
| b = metadata_binaries[0] |
| outputs += [ root_out_dir + "/" + b.breakpad ] |
| } |
| |
| # The binaries embed absolute paths to the source file, |
| # which is copied into a subdir of root_build_dir. |
| no_output_dir_leaks = false |
| } |
| |
| if (define_sdk_target) { |
| sdk_host_tool("${target_name}_sdk") { |
| forward_variables_from(invoker, "*", [ "deps" ]) |
| category = invoker.sdk_category |
| deps = [ ":$target_name" ] |
| } |
| } |
| } |