| # 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}}" ] |
| |
| # For the "gn analyze" step to work, gn needs to know about the |
| # original source files. They can't be in |sources| because then |
| # they will be compiled, so they have to be somewhere else where |
| # gn analyze looks. One alternative is the |data| list but that |
| # will affect test packaging with known bad effects on |
| # distributed testing. Putting them in this action's input list |
| # is the least bad place. |
| inputs = [] |
| foreach(f, invoker_sources - excluded_sources) { |
| # Avoid generated files and non non-source files. |
| in_source_tree = string_replace(rebase_path(f), |
| rebase_path(root_out_dir), |
| "dummy") == rebase_path(f) |
| is_source_file = get_path_info(f, "extension") == "cc" || |
| get_path_info(f, "extension") == "cpp" || |
| get_path_info(f, "extension") == "c" || |
| get_path_info(f, "extension") == "mm" |
| if (in_source_tree && is_source_file) { |
| inputs += [ f ] |
| } |
| } |
| } |
| } 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 |
| } |
| } |