xref: /aosp_15_r20/external/cronet/build/buildflag_header.gni (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1# Copyright 2015 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5# Generates a header with preprocessor defines specified by the build file.
6#
7# The flags are converted to function-style defines with mangled names and
8# code uses an accessor macro to access the values. This is to try to
9# minimize bugs where code checks whether something is defined or not, and
10# the proper header isn't included, meaning the answer will always be silently
11# false or might vary across the code base.
12#
13# In the GN template, specify build flags in the template as a list
14# of strings that encode key/value pairs like this:
15#
16#   flags = [ "ENABLE_FOO=1", "ENABLE_BAR=$enable_bar" ]
17#
18# The GN values "true" and "false" will be mapped to 0 and 1 for boolean
19# #if flags to be expressed naturally. This means you can't directly make a
20# define that generates C++ value of true or false for use in code. If you
21# REALLY need this, you can also use the string "(true)" and "(false)" to
22# prevent the rewriting.
23
24# To check the value of the flag in C code:
25#
26#   #include "path/to/here/header_file.h"
27#
28#   #if BUILDFLAG(ENABLE_FOO)
29#   ...
30#   #endif
31#
32#   const char kSpamServerUrl[] = BUILDFLAG(SPAM_SERVER_URL);
33#
34# There will be no #define called ENABLE_FOO so if you accidentally test for
35# that in an ifdef it will always be negative.
36#
37#
38# Template parameters
39#
40#   flags [required, list of strings]
41#       Flag values as described above.
42#
43#   header [required, string]
44#       File name for generated header. By default, this will go in the
45#       generated file directory for this target, and you would include it
46#       with:
47#         #include "<path_to_this_BUILD_file>/<header>"
48#
49#   header_dir [optional, string]
50#       Override the default location of the generated header. The string will
51#       be treated as a subdirectory of the root_gen_dir. For example:
52#         header_dir = "foo/bar"
53#       Then you can include the header as:
54#         #include "foo/bar/baz.h"
55#
56#   deps, public_deps, testonly, visibility
57#       Normal meaning.
58#
59#
60# Grit defines
61#
62# If one .grd file uses a flag, just add to the grit target:
63#
64#   defines = [
65#     "enable_doom_melon=$enable_doom_melon",
66#   ]
67#
68# If multiple .grd files use it, you'll want to put the defines in a .gni file
69# so it can be shared. Generally this .gni file should include all grit defines
70# for a given module (for some definition of "module"). Then do:
71#
72#   defines = ui_grit_defines
73#
74# If you forget to do this, the flag will be implicitly false in the .grd file
75# and those resources won't be compiled. You'll know because the resource
76# #define won't be generated and any code that uses it won't compile. If you
77# see a missing IDS_* string, this is probably the reason.
78#
79#
80# Example
81#
82#   buildflag_header("foo_buildflags") {
83#     header = "foo_buildflags.h"
84#
85#     flags = [
86#       # This uses the GN build flag enable_doom_melon as the definition.
87#       "ENABLE_DOOM_MELON=$enable_doom_melon",
88#
89#       # This force-enables the flag.
90#       "ENABLE_SPACE_LASER=true",
91#
92#       # This will expand to the quoted C string when used in source code.
93#       "SPAM_SERVER_URL=\"http://www.example.com/\"",
94#     ]
95#   }
96template("buildflag_header") {
97  action(target_name) {
98    script = "//build/write_buildflag_header.py"
99
100    if (defined(invoker.header_dir)) {
101      header_file = "${invoker.header_dir}/${invoker.header}"
102    } else {
103      # Compute the path from the root to this file.
104      header_file = rebase_path(".", "//") + "/${invoker.header}"
105    }
106
107    outputs = [ "$root_gen_dir/$header_file" ]
108
109    # Always write --flags to the file so it's not empty. Empty will confuse GN
110    # into thinking the response file isn't used.
111    response_file_contents = [ "--flags" ]
112    if (defined(invoker.flags)) {
113      response_file_contents += invoker.flags
114    }
115
116    args = [
117      "--output",
118      header_file,  # Not rebased, Python script puts it inside gen-dir.
119      "--rulename",
120      get_label_info(":$target_name", "label_no_toolchain"),
121      "--gen-dir",
122      rebase_path(root_gen_dir, root_build_dir),
123      "--definitions",
124      "{{response_file_name}}",
125    ]
126
127    forward_variables_from(invoker,
128                           [
129                             "deps",
130                             "public_deps",
131                             "testonly",
132                             "visibility",
133                           ])
134
135    public_deps = [ "//build:buildflag_header_h" ]
136  }
137}
138