chromium/base/allocator/partition_allocator/src/partition_alloc/buildflag_header.gni

# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# This was copied from chromium's and adapted to partition_alloc.
# Please refer to chromium's //build/buildflag_header.gni

# Generates a header with preprocessor defines specified by the build file.
#
# The flags are converted to function-style defines with mangled names and
# code uses an accessor macro to access the values. This is to try to
# minimize bugs where code checks whether something is defined or not, and
# the proper header isn't included, meaning the answer will always be silently
# false or might vary across the code base.
#
# In the GN template, specify build flags in the template as a list
# of strings that encode key/value pairs like this:
#
#   flags = [ "ENABLE_FOO=1", "ENABLE_BAR=$enable_bar" ]
#
# The GN values "true" and "false" will be mapped to 0 and 1 for boolean
# #if flags to be expressed naturally. This means you can't directly make a
# define that generates C++ value of true or false for use in code. If you
# REALLY need this, you can also use the string "(true)" and "(false)" to
# prevent the rewriting.

# The `template` creates a closure. It is important to capture the dependency
# from outside, because the template is executed from the context of the
# invoker, who uses a different current directory.
_current_dir = get_path_info(".", "abspath")

# To check the value of the flag in C code:
#
#   #include "path/to/here/header_file.h"
#
#   #if PA_BUILDFLAG(ENABLE_FOO)
#   ...
#   #endif
#
#   const char kSpamServerUrl[] = BUILDFLAG(SPAM_SERVER_URL);
#
# There will be no #define called ENABLE_FOO so if you accidentally test for
# that in an ifdef it will always be negative.
#
#
# Template parameters
#
#   flags [required, list of strings]
#       Flag values as described above.
#
#   header [required, string]
#       File name for generated header. By default, this will go in the
#       generated file directory for this target, and you would include it
#       with:
#         #include "<path_to_this_BUILD_file>/<header>"
#
#   header_dir [optional, string]
#       Override the default location of the generated header. The string will
#       be treated as a subdirectory of the root_gen_dir. For example:
#         header_dir = "foo/bar"
#       Then you can include the header as:
#         #include "foo/bar/baz.h"
#
# Example
#
#   pa_buildflag_header("foo_buildflags") {
#     header = "foo_buildflags.h"
#
#     flags = [
#       # This uses the GN build flag enable_doom_melon as the definition.
#       "ENABLE_DOOM_MELON=$enable_doom_melon",
#
#       # This force-enables the flag.
#       "ENABLE_SPACE_LASER=true",
#
#       # This will expand to the quoted C string when used in source code.
#       "SPAM_SERVER_URL=\"http://www.example.com/\"",
#     ]
#   }
template("pa_buildflag_header") {
  action(target_name) {
    script = "./write_buildflag_header.py"

    if (defined(invoker.header_dir)) {
      header_file = "${invoker.header_dir}/${invoker.header}"
    } else {
      # Compute the path from the root to this file.
      header_file = rebase_path(".", "//") + "/${invoker.header}"
    }

    outputs = [ "$root_gen_dir/$header_file" ]

    # Always write --flags to the file so it's not empty. Empty will confuse GN
    # into thinking the response file isn't used.
    response_file_contents = [ "--flags" ]
    if (defined(invoker.flags)) {
      response_file_contents += invoker.flags
    }

    args = [
      "--output",
      header_file,  # Not rebased.
      "--rulename",
      get_label_info(":$target_name", "label_no_toolchain"),
      "--gen-dir",
      rebase_path(root_gen_dir, root_build_dir),
      "--definitions",
      "{{response_file_name}}",
    ]

    forward_variables_from(invoker,
                           [
                             "deps",
                             "public_deps",
                             "testonly",
                             "visibility",
                           ])

    public_deps = [ "${_current_dir}:buildflag_macro" ]
  }
}