aboutsummaryrefslogtreecommitdiff
path: root/pw_build/gn_internal/build_target.gni
blob: 10b8ce25adf97931c0e3e2b6a50b752d843ceae1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# Copyright 2022 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_build/defaults.gni")

declare_args() {
  # Additional build targets to add as dependencies for pw_executable,
  # pw_static_library, and pw_shared_library targets. The
  # $dir_pw_build:link_deps target pulls in these libraries.
  #
  # pw_build_LINK_DEPS can be used to break circular dependencies for low-level
  # libraries such as pw_assert.
  pw_build_LINK_DEPS = []

  # The name of the GN target type used to build Pigweed executables.
  #
  # If this is a custom template, the .gni file containing the template must
  # be imported at the top of the target configuration file to make it globally
  # available.
  pw_build_EXECUTABLE_TARGET_TYPE = "executable"

  # The path to the .gni file that defines pw_build_EXECUTABLE_TARGET_TYPE.
  #
  # If pw_build_EXECUTABLE_TARGET_TYPE is not the default of `executable`, this
  # .gni file is imported to provide the template definition.
  pw_build_EXECUTABLE_TARGET_TYPE_FILE = ""
}

# This template is the underlying implementation that defines what makes
# pw_source_set, pw_executable, pw_shared_library, and pw_static_library unique.
# For more information, see the documentation at
# https://pigweed.dev/pw_build/?highlight=pw_executable#target-types
#
# In addition to the arguments supported by the underlying native target types,
# this template introduces the following arguments:
#
#  add_global_link_deps: (required) If true, adds global link dependencies as
#    specified by the current toolchain via pw_build_LINK_DEPS as dependencies
#    to all instantiations of the current target type.
#  underlying_target_type: (required) The underlying target type to use for this
#    template. This is done so different C/C++ build target types can share the
#    same underlying wrapper implementation.
#  target_type_file: (optional) If the underlying target type is not one of GN's
#    builtin types, the path to the .gni file that defines the template
#    referenced by underlying_target_type. This is exclusively to support
#    pw_exeuctable's behavior that allows a pw_executable to be essentially
#    aliased to a custom target type.
#  remove_configs: (optional) A list of configs to remove from the set of
#    default configs specified by the current toolchain configuration.
#  remove_public_deps: (optional) A list of targets to remove from the set of
#    default public_deps specified by the current toolchain configuration.
template("pw_internal_build_target") {
  assert(defined(invoker.underlying_target_type),
         "Build targets using this template must specify a target type")
  _pw_source_files = []
  _supported_toolchain_defaults = [
    "configs",
    "public_deps",
  ]

  # Boilerplate for tracking target sources.  For more information see
  # https://pigweed.dev/pw_build/#target-types
  if (defined(invoker.sources)) {
    foreach(path, invoker.sources) {
      _pw_source_files += [ path ]
    }
  }
  if (defined(invoker.public)) {
    foreach(path, invoker.public) {
      _pw_source_files += [ path ]
    }
  }

  _builtin_target_types = [
    "executable",
    "rust_library",
    "rust_proc_macro",
    "shared_library",
    "source_set",
    "static_library",
  ]
  if (filter_include(_builtin_target_types,
                     [ invoker.underlying_target_type ]) == []) {
    assert(
        defined(invoker.target_type_file) && invoker.target_type_file != "",
        string_join(
            ", ",
            [
              "Unknown target type ${invoker.underlying_target_type}",
              "set target_type_file to the .gni file that defines this type.",
            ]))
    import(invoker.target_type_file)
  }

  target(invoker.underlying_target_type, target_name) {
    forward_variables_from(
        invoker,
        "*",
        _supported_toolchain_defaults + [ "target_type_file" ])

    # Ensure that we don't overwrite metadata forwarded from the invoker above.
    if (defined(metadata)) {
      metadata.pw_source_files = _pw_source_files
    } else {
      metadata = {
        pw_source_files = _pw_source_files
      }
    }

    _default_configs =
        filter_exclude(pw_build_INTERNAL_DEFAULTS.default_configs,
                       pw_build_INTERNAL_DEFAULTS.remove_default_configs)
    if (!defined(remove_configs)) {
      remove_configs = []
    }

    # Check if configs is already defined.
    # configs will already exist if set_defaults() is used.
    if (!defined(configs)) {
      configs = []
    }

    # `configs` was not forwarded initially to support flag ordering.
    configs += filter_exclude(_default_configs, remove_configs)

    # Add the public_deps from the actual target last so they are prioritized.
    # This set of public_deps MUST be added last because it affects flag
    # ordering. If this list is added later, flags from the default list will
    # take precedence.
    if (defined(invoker.configs)) {
      configs += invoker.configs
    }

    _default_public_deps =
        filter_exclude(pw_build_INTERNAL_DEFAULTS.default_public_deps,
                       pw_build_INTERNAL_DEFAULTS.remove_default_public_deps)
    if (!defined(remove_public_deps)) {
      remove_public_deps = []
    }

    # `public_deps` was not forwarded initially to support flag ordering.
    public_deps = filter_exclude(_default_public_deps, remove_public_deps)

    # Add the public_deps from the actual target last so they are prioritized.
    # This set of public_deps MUST be added last because it affects flag
    # ordering. If this list is added later, flags from the default list will
    # take precedence.
    if (defined(invoker.public_deps)) {
      public_deps += invoker.public_deps
    }

    assert(defined(add_global_link_deps),
           "All targets MUST specify whether or not to include link deps")
    if (!defined(deps)) {
      deps = []
    }
    if (add_global_link_deps) {
      deps += [ "$dir_pw_build:link_deps" ]
    }

    if (!defined(visibility)) {
      visibility = pw_build_DEFAULT_VISIBILITY
    }
  }
}