summaryrefslogtreecommitdiff
path: root/chromium/build/config/jumbo.gni
blob: 7834edf94396e76dd0e8a69b580ad80b3926a07f (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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# Copyright 2017 The Chromium 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/split_static_library.gni")  # When someone uses that target_type
import("//build/toolchain/goma.gni")

declare_args() {
  # If true, use a jumbo build (files compiled together) to speed up
  # compilation.
  use_jumbo_build = false

  # A list of build targets to exclude from jumbo builds, for optimal
  # round trip time when frequently changing a set of cpp files. The
  # targets can be just the short name (in which case it matches any
  # target with that name), a directory prefixed with the root
  # specifier //, or a full build target label.
  #
  # Example:
  # These would all exclude the "browser" target in a file
  # content/browser/BUILD.gn, and potentially more.
  #
  # jumbo_build_excluded = [ "browser" ]
  # jumbo_build_excluded = [ "//content/browser" ]
  # jumbo_build_excluded = [ "//content/browser:browser" ]
  jumbo_build_excluded = []

  # How many files to group on average. Smaller numbers give more
  # parallellism, higher numbers give less total CPU usage. Higher
  # numbers also give longer single-file recompilation times.
  #
  # Recommendations:
  # Higher numbers than 100 does not reduce wall clock compile times
  # even for 4 cores or less so no reason to go higher than 100.
  # Going from 50 to 100 with a 4 core CPU saves about 3% CPU time and
  # 3% wall clock time in a tree with blink, v8 and content
  # jumbofied. At the same time it increases the compile time for the
  # largest jumbo chunks by 10-20% and reduces the chance to use all
  # available CPU cores. So set the default to 50 to balance between
  # high and low-core build performance. -1 means do the default which
  # varies depending on whether goma is enabled.
  jumbo_file_merge_limit = -1
}

# Normal builds benefit from lots of jumbification
jumbo_file_merge_default = 50

# Goma builds benefit from more parallelism
jumbo_file_merge_goma = 8

# Use one of the targets jumbo_source_set, jumbo_static_library,
# jumbo_split_static_library or jumbo_component to generate a target
# which merges sources if possible to compile much faster.
#
# Special values.
#
#   target_type
#      The kind of target to build. For example the string
#      "static_library".
#
#   always_build_jumbo
#      If set and set to true, then use jumbo compile even when it is
#      globally disabled. Otherwise it has no effect.
#
#   never_build_jumbo
#      If set and set to true, then do not jumbo compile even if it is
#      globally enabled. Otherwise it has no effect.
#
#   jumbo_excluded_sources
#      If set to a list of files, those files will not be merged with
#      the rest. This can be necessary if merging the files causes
#      compilation issues and fixing the issues is impractical.
template("internal_jumbo_target") {
  use_jumbo_build_for_target = use_jumbo_build
  if (defined(invoker.always_build_jumbo) && invoker.always_build_jumbo) {
    use_jumbo_build_for_target = true
  }
  if (defined(invoker.never_build_jumbo) && invoker.never_build_jumbo) {
    use_jumbo_build_for_target = false
  }

  foreach(excluded_target, jumbo_build_excluded) {
    if (excluded_target == target_name ||
        excluded_target == get_label_info(":" + target_name, "dir") ||
        excluded_target ==
        get_label_info(":" + target_name, "label_no_toolchain")) {
      use_jumbo_build_for_target = false
    }
  }

  excluded_sources = []
  if (defined(invoker.jumbo_excluded_sources)) {
    excluded_sources = invoker.jumbo_excluded_sources
  }

  if (defined(invoker.sources)) {
    invoker_sources = invoker.sources
  } else {
    invoker_sources = []
  }

  gen_target_dir = invoker.target_gen_dir

  not_needed([ "gen_target_dir" ])  # Prevent "unused variable".

  if (use_jumbo_build_for_target) {
    jumbo_files = []

    # Split the sources list into chunks that are not excessively large
    current_file_index = 0
    next_chunk_start = 0
    next_chunk_number = 1
    merge_limit = jumbo_file_merge_limit
    if (merge_limit == -1) {
      if (use_goma) {
        merge_limit = jumbo_file_merge_goma
      } else {
        merge_limit = jumbo_file_merge_default
      }
    }
    has_c_file = false
    has_objective_c_file = false
    sources_in_jumbo_files = []
    assert(merge_limit > 0)
    foreach(source_file, invoker_sources) {
      source_ext = get_path_info(source_file, "extension")
      is_source_file = true
      if (source_ext == "c") {
        has_c_file = true
      } else if (source_ext == "mm") {
        has_objective_c_file = true
      } else if (source_ext == "cc" || source_ext == "cpp") {
        if (current_file_index == next_chunk_start) {
          jumbo_files += [ "$gen_target_dir/" + target_name + "_jumbo_" +
                           next_chunk_number + ".cc" ]
          next_chunk_number += 1
          next_chunk_start += merge_limit
        }
        current_file_index += 1
      } else {
        is_source_file = false
      }
      if (is_source_file) {
        sources_in_jumbo_files += [ source_file ]
      }
    }

    if (jumbo_files == [] || current_file_index == 1) {
      # Empty sources list or a sources list with only header files or
      # at most one non-header file.
      use_jumbo_build_for_target = false
      not_needed([
                   "sources_in_jumbo_files",
                   "current_file_index",
                   "next_chunk_start",
                   "next_chunk_number",
                 ])
    }

    if (has_c_file) {
      jumbo_files += [ "$gen_target_dir/" + target_name + "_jumbo_c.c" ]
    }
    if (has_objective_c_file) {
      jumbo_files += [ "$gen_target_dir/" + target_name + "_jumbo_mm.mm" ]
    }
  }

  if (use_jumbo_build_for_target) {
    merge_action_name = target_name + "__jumbo_merge"
    sources_in_jumbo_files -= excluded_sources

    # Create an action that calls a script that merges all the source files.
    action(merge_action_name) {
      script = "//build/config/merge_for_jumbo.py"
      response_file_contents =
          rebase_path(sources_in_jumbo_files, root_build_dir)
      outputs = jumbo_files
      args = [ "--outputs" ] + rebase_path(outputs, root_build_dir) +
             [ "--file-list={{response_file_name}}" ]
    }
  } else {
    # If the list subtraction triggers a gn error,
    # jumbo_excluded_sources lists a file that is not in sources.
    sources_after_exclusion = invoker_sources - excluded_sources
    not_needed([ "sources_after_exclusion" ])
  }

  target_type = invoker.target_type
  if (use_jumbo_build_for_target && target_type == "split_static_library") {
    # Meaningless and also impossible if split_count > len(jumbo_files)
    target_type = "static_library"
    not_needed(invoker, [ "split_count" ])
  }

  # Perform the actual operation, either on the original sources or
  # the sources post-jumbo merging.
  target(target_type, target_name) {
    deps = []
    if (defined(invoker.deps)) {
      deps += invoker.deps
    }

    # Take everything else not handled above from the invoker.
    variables_to_not_forward = [ "deps" ]
    if (use_jumbo_build_for_target) {
      deps += [ ":" + merge_action_name ]
      variables_to_not_forward += [ "sources" ]
      assert(jumbo_files != [])
      set_sources_assignment_filter([])  # Prefiltered.
      sources = invoker_sources - sources_in_jumbo_files + jumbo_files

      # Change include_dirs to make sure that the jumbo file can find its
      # #included files.
      variables_to_not_forward += [ "include_dirs" ]
      include_dirs = []
      if (defined(invoker.include_dirs)) {
        include_dirs = invoker.include_dirs
      }
      include_dirs += [ root_build_dir ]
    }
    forward_variables_from(invoker, "*", variables_to_not_forward)
  }
}

# See documentation above by "internal_jumbo_target".
template("jumbo_source_set") {
  internal_jumbo_target(target_name) {
    target_type = "source_set"
    forward_variables_from(invoker, "*")
  }
}

set_defaults("jumbo_source_set") {
  # This sets the default list of configs when the jumbo_source_set target
  # is defined. The default_compiler_configs comes from BUILDCONFIG.gn and
  # is the list normally applied to static libraries and source sets.
  configs = default_compiler_configs
}

# See documentation above by "internal_jumbo_target".
template("jumbo_static_library") {
  internal_jumbo_target(target_name) {
    target_type = "static_library"
    forward_variables_from(invoker, "*")
  }
}

set_defaults("jumbo_static_library") {
  # This sets the default list of configs when the jumbo_static_library target
  # is defined. The default_compiler_configs comes from BUILDCONFIG.gn and
  # is the list normally applied to static libraries and source sets.
  configs = default_compiler_configs
}

# See documentation above by "internal_jumbo_target".
template("jumbo_split_static_library") {
  internal_jumbo_target(target_name) {
    target_type = "split_static_library"
    forward_variables_from(invoker, "*")
  }
}

set_defaults("jumbo_split_static_library") {
  # This sets the default list of configs when the
  # jumbo_split_static_library target is defined. The
  # default_compiler_configs comes from BUILDCONFIG.gn and is the list
  # normally applied to static libraries and source sets.
  configs = default_compiler_configs
}

# See documentation above by "internal_jumbo_target".
template("jumbo_component") {
  internal_jumbo_target(target_name) {
    target_type = "component"
    forward_variables_from(invoker, "*")
  }
}

set_defaults("jumbo_component") {
  # This sets the default list of configs when the jumbo_component
  # target is defined. This code is a clone of set_defaults for the
  # ordinary "component" template.
  if (is_component_build) {
    configs = default_shared_library_configs
    if (is_android) {
      configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
    }
  } else {
    configs = default_compiler_configs
  }
}