You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
387 lines
14 KiB
387 lines
14 KiB
# Copyright 2020 The Pigweed Authors
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
# use this file except in compliance with the License. You may obtain a copy of
|
|
# the License at
|
|
#
|
|
# https://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations under
|
|
# the License.
|
|
|
|
import("//build_overrides/pigweed.gni")
|
|
|
|
import("$dir_pw_toolchain/universal_tools.gni")
|
|
|
|
declare_args() {
|
|
# Scope defining the current toolchain. Contains all of the arguments required
|
|
# by the generate_toolchain template. This should NOT be manually modified.
|
|
pw_toolchain_SCOPE = {
|
|
}
|
|
|
|
# Prefix for compilation commands (e.g. the path to a Goma or CCache compiler
|
|
# launcher). Example for ccache:
|
|
# gn gen out --args='pw_command_launcher="ccache"'
|
|
pw_command_launcher = ""
|
|
}
|
|
|
|
# Creates a toolchain target.
|
|
#
|
|
# Args:
|
|
# ar: (required) String indicating the archive tool to use.
|
|
# cc: (required) String indicating the C compiler to use.
|
|
# cxx: (required) String indicating the C++ compiler to use.
|
|
# is_host_toolchain: (optional) Boolean indicating if the outputs are meant
|
|
# for the $host_os.
|
|
# final_binary_extension: (optional) The extension to apply to final linked
|
|
# binaries.
|
|
# link_whole_archive: (optional) Boolean indicating if the linker should load
|
|
# all object files when resolving symbols.
|
|
# link_group: (optional) Boolean indicating if the linker should use
|
|
# a group to resolve circular dependencies between artifacts.
|
|
# generate_from: (optional) The full target name of the toolchain that can
|
|
# trigger this toolchain to be generated. GN only allows one toolchain to
|
|
# be generated at a given target path, so if multiple toolchains parse the
|
|
# same generate_toolchain target only one should declare a toolchain. This
|
|
# is primarily to allow generating sub-toolchains. Defaults to
|
|
# default_toolchain.
|
|
# defaults: (required) A scope setting GN build arg values to apply to GN
|
|
# targets in this toolchain. These take precedence over args.gni settings.
|
|
#
|
|
# The defaults scope should contain values for builtin GN arguments:
|
|
# current_cpu: The CPU of the toolchain.
|
|
# Well known values include "arm", "arm64", "x64", "x86", and "mips".
|
|
# current_os: The OS of the toolchain. Defaults to "".
|
|
# Well known values include "win", "mac", "linux", "android", and "ios".
|
|
#
|
|
# TODO(pwbug/333): This should be renamed to pw_generate_toolchain.
|
|
template("generate_toolchain") {
|
|
assert(defined(invoker.defaults), "toolchain is missing 'defaults'")
|
|
|
|
# On the default toolchain invocation, you typically need to generate all
|
|
# toolchains you encounter. For sub-toolchains, they must be generated from
|
|
# the context of their parent.
|
|
if (defined(invoker.generate_from)) {
|
|
_generate_toolchain =
|
|
get_label_info(invoker.generate_from, "label_no_toolchain") ==
|
|
current_toolchain
|
|
} else {
|
|
_generate_toolchain = default_toolchain == current_toolchain
|
|
}
|
|
|
|
if (_generate_toolchain) {
|
|
# TODO(amontanez): This should be renamed to build_args as "defaults" isn't
|
|
# sufficiently descriptive.
|
|
invoker_toolchain_args = invoker.defaults
|
|
|
|
# These values should always be set as they influence toolchain
|
|
# behavior, but allow them to be unset as a transitional measure.
|
|
if (!defined(invoker_toolchain_args.current_cpu)) {
|
|
invoker_toolchain_args.current_cpu = ""
|
|
}
|
|
if (!defined(invoker_toolchain_args.current_os)) {
|
|
invoker_toolchain_args.current_os = ""
|
|
}
|
|
|
|
# Determine OS of toolchain, which is the builtin argument "current_os".
|
|
toolchain_os = invoker_toolchain_args.current_os
|
|
|
|
toolchain(target_name) {
|
|
# Uncomment this line to see which toolchains generate other toolchains.
|
|
# print("Generating toolchain: ${target_name} by ${current_toolchain}")
|
|
|
|
assert(defined(invoker.cc), "toolchain is missing 'cc'")
|
|
tool("asm") {
|
|
if (pw_command_launcher != "") {
|
|
command_launcher = pw_command_launcher
|
|
}
|
|
depfile = "{{output}}.d"
|
|
command = string_join(" ",
|
|
[
|
|
invoker.cc,
|
|
"-MMD -MF $depfile", # Write out dependencies.
|
|
"{{asmflags}}",
|
|
"{{cflags}}",
|
|
"{{defines}}",
|
|
"{{include_dirs}}",
|
|
"-c {{source}}",
|
|
"-o {{output}}",
|
|
])
|
|
depsformat = "gcc"
|
|
description = "as {{output}}"
|
|
outputs = [
|
|
# Use {{source_file_part}}, which includes the extension, instead of
|
|
# {{source_name_part}} so that object files created from <file_name>.c
|
|
# and <file_name>.cc sources are unique.
|
|
"{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
|
|
]
|
|
}
|
|
|
|
tool("cc") {
|
|
if (pw_command_launcher != "") {
|
|
command_launcher = pw_command_launcher
|
|
}
|
|
depfile = "{{output}}.d"
|
|
command = string_join(" ",
|
|
[
|
|
invoker.cc,
|
|
"-MMD -MF $depfile", # Write out dependencies.
|
|
"{{cflags}}",
|
|
"{{cflags_c}}", # Must come after {{cflags}}.
|
|
"{{defines}}",
|
|
"{{include_dirs}}",
|
|
"-c {{source}}",
|
|
"-o {{output}}",
|
|
])
|
|
depsformat = "gcc"
|
|
description = "cc {{output}}"
|
|
outputs = [
|
|
"{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
|
|
]
|
|
}
|
|
|
|
assert(defined(invoker.cxx), "toolchain is missing 'cxx'")
|
|
tool("cxx") {
|
|
if (pw_command_launcher != "") {
|
|
command_launcher = pw_command_launcher
|
|
}
|
|
depfile = "{{output}}.d"
|
|
command = string_join(" ",
|
|
[
|
|
invoker.cxx,
|
|
"-MMD -MF $depfile", # Write out dependencies.
|
|
"{{cflags}}",
|
|
"{{cflags_cc}}", # Must come after {{cflags}}.
|
|
"{{defines}}",
|
|
"{{include_dirs}}",
|
|
"-c {{source}}",
|
|
"-o {{output}}",
|
|
])
|
|
depsformat = "gcc"
|
|
description = "c++ {{output}}"
|
|
outputs = [
|
|
"{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
|
|
]
|
|
}
|
|
|
|
tool("objc") {
|
|
if (pw_command_launcher != "") {
|
|
command_launcher = pw_command_launcher
|
|
}
|
|
depfile = "{{output}}.d"
|
|
command =
|
|
string_join(" ",
|
|
[
|
|
invoker.cc,
|
|
"-MMD -MF $depfile", # Write out dependencies.
|
|
"{{cflags}}",
|
|
"{{cflags_objc}}", # Must come after {{cflags}}.
|
|
"{{defines}}",
|
|
"{{include_dirs}}",
|
|
"{{framework_dirs}}",
|
|
"-c {{source}}",
|
|
"-o {{output}}",
|
|
])
|
|
depsformat = "gcc"
|
|
description = "objc {{output}}"
|
|
outputs = [
|
|
"{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
|
|
]
|
|
}
|
|
|
|
tool("objcxx") {
|
|
if (pw_command_launcher != "") {
|
|
command_launcher = pw_command_launcher
|
|
}
|
|
depfile = "{{output}}.d"
|
|
command =
|
|
string_join(" ",
|
|
[
|
|
invoker.cxx,
|
|
"-MMD -MF $depfile", # Write out dependencies.
|
|
"{{cflags}}",
|
|
"{{cflags_objcc}}", # Must come after {{cflags}}.
|
|
"{{defines}}",
|
|
"{{include_dirs}}",
|
|
"{{framework_dirs}}",
|
|
"-c {{source}}",
|
|
"-o {{output}}",
|
|
])
|
|
depsformat = "gcc"
|
|
description = "objc++ {{output}}"
|
|
outputs = [
|
|
"{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
|
|
]
|
|
}
|
|
|
|
assert(defined(invoker.ar), "toolchain is missing 'ar'")
|
|
tool("alink") {
|
|
if (host_os == "win") {
|
|
rspfile = "{{output}}.rsp"
|
|
rspfile_content = "{{inputs}}"
|
|
rm_command = "del /F /Q \"{{output}}\" 2> NUL"
|
|
command = "cmd /c \"($rm_command) & ${invoker.ar} {{arflags}} rcs {{output}} @$rspfile\""
|
|
} else {
|
|
command = "rm -f {{output}} && ${invoker.ar} {{arflags}} rcs {{output}} {{inputs}}"
|
|
}
|
|
|
|
description = "ar {{target_output_name}}{{output_extension}}"
|
|
outputs =
|
|
[ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ]
|
|
default_output_extension = ".a"
|
|
default_output_dir = "{{target_out_dir}}/lib"
|
|
}
|
|
|
|
lib_switch = "-l"
|
|
lib_dir_switch = "-L"
|
|
|
|
_link_outfile =
|
|
"{{output_dir}}/{{target_output_name}}{{output_extension}}"
|
|
_link_mapfile = "{{output_dir}}/{{target_output_name}}.map"
|
|
_link_flags = [
|
|
invoker.cxx,
|
|
"{{ldflags}}",
|
|
]
|
|
|
|
if (toolchain_os == "mac" || toolchain_os == "ios") {
|
|
_link_flags += [
|
|
# Output a map file that shows symbols and their location.
|
|
"-Wl,-map,$_link_mapfile",
|
|
|
|
# Delete unreferenced sections. Helpful with -ffunction-sections.
|
|
"-Wl,-dead_strip",
|
|
]
|
|
} else {
|
|
_link_flags += [
|
|
# Output a map file that shows symbols and their location.
|
|
"-Wl,-Map,$_link_mapfile",
|
|
|
|
# Delete unreferenced sections. Helpful with -ffunction-sections.
|
|
"-Wl,--gc-sections",
|
|
]
|
|
}
|
|
|
|
_link_group = defined(invoker.link_group) && invoker.link_group
|
|
if (_link_group) {
|
|
_link_flags += [ "-Wl,--start-group" ]
|
|
}
|
|
_link_flags += [ "{{inputs}}" ]
|
|
_link_flags += [ "{{frameworks}}" ]
|
|
|
|
if (defined(invoker.link_whole_archive) && invoker.link_whole_archive) {
|
|
# Load all object files from all libraries to resolve symbols.
|
|
# Short of living in the ideal world where all dependency graphs
|
|
# among static libs are acyclic and all developers diligently
|
|
# express such graphs in terms that GN understands, this is the
|
|
# safest option.
|
|
# Make sure you use this with --gc-sections, otherwise the
|
|
# resulting binary will contain every symbol defined in every
|
|
# input file and every static library. That could be quite a lot.
|
|
_link_flags += [
|
|
"-Wl,--whole-archive",
|
|
"{{libs}}",
|
|
"-Wl,--no-whole-archive",
|
|
]
|
|
} else {
|
|
_link_flags += [ "{{libs}}" ]
|
|
}
|
|
|
|
if (_link_group) {
|
|
_link_flags += [ "-Wl,--end-group" ]
|
|
}
|
|
_link_flags += [ "-o $_link_outfile" ]
|
|
|
|
_link_command = string_join(" ", _link_flags)
|
|
|
|
tool("link") {
|
|
command = _link_command
|
|
description = "ld $_link_outfile"
|
|
outputs = [
|
|
_link_outfile,
|
|
_link_mapfile,
|
|
]
|
|
default_output_dir = "{{target_out_dir}}/bin"
|
|
|
|
if (defined(invoker.final_binary_extension)) {
|
|
default_output_extension = invoker.final_binary_extension
|
|
} else if (toolchain_os == "win") {
|
|
default_output_extension = ".exe"
|
|
} else {
|
|
default_output_extension = ""
|
|
}
|
|
}
|
|
|
|
tool("solink") {
|
|
command = _link_command + " -shared"
|
|
description = "ld -shared $_link_outfile"
|
|
outputs = [
|
|
_link_outfile,
|
|
_link_mapfile,
|
|
]
|
|
default_output_dir = "{{target_out_dir}}/lib"
|
|
default_output_extension = ".so"
|
|
}
|
|
|
|
tool("stamp") {
|
|
# GN-ism: GN gets mad if you directly forward the contents of
|
|
# pw_universal_stamp.
|
|
_stamp = pw_universal_stamp
|
|
forward_variables_from(_stamp, "*")
|
|
}
|
|
|
|
tool("copy") {
|
|
# GN-ism: GN gets mad if you directly forward the contents of
|
|
# pw_universal_copy.
|
|
_copy = pw_universal_copy
|
|
forward_variables_from(_copy, "*")
|
|
}
|
|
|
|
# Build arguments to be overridden when compiling cross-toolchain:
|
|
#
|
|
# pw_toolchain_defaults: A scope setting defaults to apply to GN targets
|
|
# in this toolchain. It is analogous to $pw_target_defaults in
|
|
# $dir_pigweed/pw_vars_default.gni.
|
|
#
|
|
# pw_toolchain_SCOPE: A copy of the invoker scope that defines the
|
|
# toolchain. Used for generating derivative toolchains.
|
|
#
|
|
toolchain_args = {
|
|
pw_toolchain_SCOPE = {
|
|
}
|
|
pw_toolchain_SCOPE = {
|
|
forward_variables_from(invoker, "*")
|
|
name = target_name
|
|
}
|
|
forward_variables_from(invoker_toolchain_args, "*")
|
|
}
|
|
}
|
|
} else {
|
|
not_needed(invoker, "*")
|
|
group(target_name) {
|
|
}
|
|
}
|
|
}
|
|
|
|
# Creates a series of toolchain targets with common compiler options.
|
|
#
|
|
# Args:
|
|
# toolchains: List of scopes defining each of the desired toolchains.
|
|
# The scope must contain a "name" variable; other variables are forwarded to
|
|
# $generate_toolchain.
|
|
template("generate_toolchains") {
|
|
not_needed([ "target_name" ])
|
|
assert(defined(invoker.toolchains),
|
|
"generate_toolchains must be called with a list of toolchains")
|
|
|
|
# Create a target for each of the desired toolchains, appending its own cflags
|
|
# and ldflags to the common ones.
|
|
foreach(_toolchain, invoker.toolchains) {
|
|
generate_toolchain(_toolchain.name) {
|
|
forward_variables_from(_toolchain, "*", [ "name" ])
|
|
}
|
|
}
|
|
}
|