blob: 15993b3cd6021a88f52828ea215ec1a5e5dc31c3 [file] [log] [blame]
# Copyright 2018 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
declare_args() {
# The OS build is running on.
OS = ""
# Specifies pkg-config program to retrieve information about packages.
pkg_config = ""
# The logical root directory for headers and libraries.
# Trailing slash should not be added (except root path).
sysroot = ""
# The libdir of the target board. e.g. /usr/lib64
libdir = ""
# The path to the directory where build artifacts are located.
build_root = ""
# The path to src/platform2.
platform2_root = ""
# Libbase revision number read from BASE_VER variable or file.
libbase_ver = ""
# Set true to allow C++ code to use exceptions.
enable_exceptions = false
# Set true if clang is used for C compiler.
clang_cc = false
# Set true if clang is used for C++ compiler.
clang_cxx = false
# Additional flags for C compiler.
external_cflags = []
# Additional flags for C++ compiler.
external_cxxflags = []
# Additional flags for C and C++ preprocessor.
external_cppflags = []
# Additional flags for C and C++ linker.
external_ldflags = []
# Whether to link against libstdc++fs. Set this to true if the compiler
# version requires -lstdc++fs to use std::filesystem. Useful when compiling
# common-mk projects outside Chrome OS where there are many compiler
# variations.
link_stdcppfs = false
# Set this to true if you want to activate the debug mode.
is_debug = false
# Subdir in platform2 where the package is located.
# TODO(oka): This value is public because it is used in ap/ package for common
# targets to use different default flags based on the package to be built.
# This is hacky, so remove such usages and move this variable back to
# gn_root/BUILD.gn .
platform_subdir = ""
}
import("//common-mk/use.gni")
assert(pkg_config != "", "pkg-config script path must be set")
assert(libbase_ver != -1, "libbase_ver must be set")
assert(libdir != "", "libdir must be set")
if (target_os == "") {
target_os = host_os
}
if (target_cpu == "") {
target_cpu = host_cpu
}
if (current_cpu == "") {
current_cpu = target_cpu
}
if (current_os == "") {
current_os = target_os
}
# Practically sysroot is used as a prefix of paths, e.g.
# "${sysroot}/usr/include". If sysroot is root (= "/"), it will be
# "//usr/include". However, in GN, paths starting with "//" represents the path
# to the GN root, rather than the file system root, which is unexpected.
# To support that case, replace sysroot with "/.", if sysroot is "/".
if (sysroot == "/") {
sysroot = "/."
}
# All binary targets will get this list of configs by default.
_binary_target_configs = [ "//common-mk:compiler_defaults" ]
if (!enable_exceptions) {
_binary_target_configs += [ "//common-mk:no_exceptions" ]
}
if (!clang_cc) {
_binary_target_configs += [ "//common-mk:gcc_cflags_c" ]
}
if (!clang_cxx) {
_binary_target_configs += [ "//common-mk:gcc_cflags_cc" ]
}
set_defaults("executable") {
configs = _binary_target_configs
configs += [ "//common-mk:pie" ]
}
set_defaults("static_library") {
configs = _binary_target_configs
configs += [
"//common-mk:pie",
"//common-mk:use_thin_archive",
]
}
set_defaults("shared_library") {
configs = _binary_target_configs
configs += [ "//common-mk:pic" ]
}
set_defaults("source_set") {
configs = _binary_target_configs
}
set_default_toolchain("//common-mk/toolchain")
# In Chrome OS, pkg-config is commonly and widely used.
# It is not natively supported by GN. Instead, here a few special fields are
# injected to the executable, shared_library and static_library targets
# to support pkg-config.
# src_install and src_test settings are also written in the same way.
#
# install_path exports metadata for installing the file built by the target.
# For example,
# - executable("my_executable") # template invocation
# is expanded to:
# - executable("my_executable") # GN built-in function invocation
# - install_config("my_executable-install_config")
# In this case ":my_executable" is usually joined to the dependency chain from
# the root (":all") by the BUILD.gn that uses this template. However, the
# ":my_executable-install_config" is not. So we chain it by adding to deps.
# ":all" --> ":my_executable" -(add this dep)-> ":my_executable-install_config"
#
# Args:
# pkg_deps(optional): A list of package names to be depend.
# A corresponding config is created, and then injected to |configs|.
# public_pkg_deps(optional): Similart to pkg_deps, but injected to
# |public_configs| instead.
# all_dependent_pkg_deps(optional): Similar to pkg_deps, but injected to
# |all_dependent_configs|.
# run_test(optional): A boolean if this is a unittest program that should be
# automatically run. A corresponding metadata is injected to itself.
# test_config(optional): A scope of configs for tests.
# A corresponding metadata is injected to itself.
# install_path(optional): A path to install into.
# A corresponding group is created, and then injected to |deps|.
import("//common-mk/install_config.gni")
import("//common-mk/pkg_config.gni")
template("_generate_config_rule") {
if (defined(invoker.pkg_deps) && invoker.pkg_deps != []) {
_pkg_deps_name = "_${target_name}-pkg_deps-config"
pkg_config(_pkg_deps_name) {
pkg_deps = invoker.pkg_deps
}
}
if (defined(invoker.public_pkg_deps) && invoker.public_pkg_deps != []) {
_public_pkg_deps_name = "_${target_name}-public_pkg_deps-config"
pkg_config(_public_pkg_deps_name) {
pkg_deps = invoker.public_pkg_deps
}
}
if (defined(invoker.all_dependent_pkg_deps) &&
invoker.all_dependent_pkg_deps != []) {
_all_dependent_pkg_deps_name =
"_${target_name}-all_dependent_pkg_deps-config"
pkg_config(_all_dependent_pkg_deps_name) {
pkg_deps = invoker.all_dependent_pkg_deps
}
}
if (defined(invoker.install_path)) {
_install_config_name = "_${target_name}-install_config"
source_name = invoker.target_name
if (defined(invoker.output_name)) {
source_name = invoker.output_name
}
source_dir = invoker.root_build_dir
if (defined(invoker.output_dir)) {
source_dir = invoker.output_dir
}
install_config(_install_config_name) {
if (defined(invoker.target_type)) {
type = invoker.target_type
}
if (invoker.target_type == "shared_library") {
sources = [ "${source_dir}/lib/${source_name}.so" ]
} else if (invoker.target_type == "static_library") {
sources = [ "${source_dir}/${source_name}.a" ]
} else {
sources = [ "${source_dir}/${source_name}" ]
}
install_path = invoker.install_path
}
}
target(invoker.target_type, target_name) {
forward_variables_from(invoker,
"*",
[
"all_dependent_pkg_deps",
"install_path",
"metadata",
"pkg_deps",
"public_pkg_deps",
"run_test",
"target_type",
"test_config",
])
if (defined(_pkg_deps_name)) {
if (!defined(configs)) {
configs = []
}
configs += [ ":${_pkg_deps_name}" ]
}
if (defined(_public_pkg_deps_name)) {
if (!defined(public_configs)) {
public_configs = []
}
public_configs += [ ":${_public_pkg_deps_name}" ]
}
if (defined(_all_dependent_pkg_deps_name)) {
if (!defined(all_dependent_configs)) {
all_dependent_configs = []
}
all_dependent_configs += [ ":${_all_dependent_pkg_deps_name}" ]
}
if (defined(_install_config_name)) {
# Add deps to have install_config rule joined to the dependency chain.
# The dependency direction is opposite to the real information flow, but
# it does not matter here because the installation is done in the
# src_install ebuild phase after all build is finished.
if (!defined(deps)) {
deps = []
}
deps += [ ":${_install_config_name}" ]
}
_run_test = defined(invoker.run_test) && invoker.run_test
if (defined(invoker.metadata) || _run_test) {
metadata = {
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
if (_run_test) {
_run_test = [ true ]
if (defined(invoker.test_config)) {
_test_config = [ invoker.test_config ]
}
}
}
}
}
}
# Add variables for exporting install configs of files generated by action targets.
#
# install_configs:
# Optional list of scopes that specify installation configuration.
# Each scope can contain these values:
# path: Install destination.
# files: Optional list of files to be installed.
# This should be a subset of outputs.
# When this is omitted, the enclosing install_configs can have only
# one item, and all the files in the outputs are installed.
# options: Optional string. Specifies the insopts.
template("action") {
if (defined(invoker.install_configs)) {
_installs = []
_i = 0
_all_files = false
foreach(c, invoker.install_configs) {
_install_config_name = "_${target_name}-${_i}-install_config"
install_config(_install_config_name) {
if (defined(c.files)) {
sources = c.files
} else {
sources = invoker.outputs
}
install_path = c.path
if (defined(c.options)) {
options = c.options
}
}
_installs += [ ":${_install_config_name}" ]
_i = _i + 1
if (!defined(c.files)) {
_all_files = true
}
}
# _i here is the length of invoker.intall_configs.
# Note that GN does not provide a function to get a list length.
assert(
_i == 1 || !_all_files,
"|install_configs| should have only one entry when |files| is omitted inside it.")
}
action(target_name) {
forward_variables_from(invoker, "*", [ "install_configs" ])
if (defined(_installs)) {
# Add deps so that data export is added to the dependency chain.
# See the comments in _generate_config_rule.
if (!defined(deps)) {
deps = []
}
deps += _installs
}
}
}
template("executable") {
_generate_config_rule(target_name) {
forward_variables_from(invoker, "*")
target_type = "executable"
}
}
template("shared_library") {
_generate_config_rule(target_name) {
forward_variables_from(invoker, "*")
target_type = "shared_library"
}
}
template("static_library") {
_generate_config_rule(target_name) {
forward_variables_from(invoker, "*")
target_type = "static_library"
}
}