[gn build] Process .def.in files in llvm/Config and add lib/Target/BUILD.gn

Tweak write_cmake_config.py to also handle variable references looking @FOO@
(matching CMake's configure_file() function), and make it replace '\' 'n' in
values with a newline literal since there's no good portable way of passing a
real newline literal on a command line.

Use that to process all the .def.in files in llvm/include/Config and add
llvm/lib/Target/BUILD.gn, which (indirectly, through llvm-c/Target.h) includes
them.

Differential Revision: https://reviews.llvm.org/D55184

llvm-svn: 348503
This commit is contained in:
Nico Weber 2018-12-06 17:42:35 +00:00
parent 96f6963708
commit 1be23a901f
5 changed files with 115 additions and 13 deletions

View File

@ -2,16 +2,17 @@
"""Emulates the bits of CMake's configure_file() function needed in LLVM. """Emulates the bits of CMake's configure_file() function needed in LLVM.
The CMake build uses configure_file() for several things. This emulates that The CMake build uses configure_file() for several things. This emulates that
function for the GN build. In the GN build, this runs at build time, instead function for the GN build. In the GN build, this runs at build time instead
of at generator time. of at generator time.
Takes a list of KEY=VALUE pairs (where VALUE can be empty). Takes a list of KEY=VALUE pairs (where VALUE can be empty).
On each line, replaces ${KEY} with VALUE. The sequence `\` `n` in each VALUE is replaced by a newline character.
After that, also handles these special cases (note that FOO= sets the value of On each line, replaces '${KEY}' or '@KEY@' with VALUE.
FOO to the empty string, which is falsy, but FOO=0 sets it to '0' which is
truthy): Then, handles these special cases (note that FOO= sets the value of FOO to the
empty string, which is falsy, but FOO=0 sets it to '0' which is truthy):
1.) #cmakedefine01 FOO 1.) #cmakedefine01 FOO
Checks if key FOO is set to a truthy value, and depending on that prints Checks if key FOO is set to a truthy value, and depending on that prints
@ -28,8 +29,7 @@ truthy):
/* #undef FOO */ /* #undef FOO */
Fails if any of the KEY=VALUE arguments aren't needed for processing the Fails if any of the KEY=VALUE arguments aren't needed for processing the
.h.cmake file, or if the .h.cmake file has unreplaced ${VAR} references after input file, or if the input file references keys that weren't passed in.
processing all values.
""" """
from __future__ import print_function from __future__ import print_function
@ -53,18 +53,19 @@ def main():
values = {} values = {}
for value in args.values: for value in args.values:
key, val = value.split('=', 1) key, val = value.split('=', 1)
values[key] = val values[key] = val.replace('\\n', '\n')
unused_values = set(values.keys()) unused_values = set(values.keys())
# Matches e.g. '${CLANG_FOO}' and captures CLANG_FOO in group 1. # Matches e.g. '${FOO}' or '@FOO@' and captures FOO in group 1 or 2.
var_re = re.compile(r'\$\{([^}]*)\}') var_re = re.compile(r'\$\{([^}]*)\}|@([^@]*)@')
in_lines = open(args.input).readlines() in_lines = open(args.input).readlines()
out_lines = [] out_lines = []
for in_line in in_lines: for in_line in in_lines:
def repl(m): def repl(m):
unused_values.discard(m.group(1)) key = m.group(1) or m.group(2)
return values[m.group(1)] unused_values.discard(key)
return values[key]
in_line = var_re.sub(repl, in_line) in_line = var_re.sub(repl, in_line)
if in_line.startswith('#cmakedefine01 '): if in_line.startswith('#cmakedefine01 '):
_, var = in_line.split() _, var = in_line.split()

View File

@ -1,6 +1,7 @@
group("default") { group("default") {
deps = [ deps = [
"//llvm/lib/Object", "//llvm/lib/Object",
"//llvm/lib/Target",
"//llvm/tools/llvm-undname", "//llvm/tools/llvm-undname",
"//llvm/utils/TableGen:llvm-tblgen", "//llvm/utils/TableGen:llvm-tblgen",
] ]

View File

@ -7,7 +7,8 @@ import("//llvm/utils/gn/build/libs/xml/enable.gni")
import("//llvm/utils/gn/build/libs/zlib/enable.gni") import("//llvm/utils/gn/build/libs/zlib/enable.gni")
import("//llvm/version.gni") import("//llvm/version.gni")
# Contains actions to create config.h, llvm-config.h and abi-breaking.h. # Contains actions to create config.h, llvm-config.h, abi-breaking.h,
# and the various .def files used by llvm/lib/Target.
# Other than in the cmake build, these are created at build time, not at # Other than in the cmake build, these are created at build time, not at
# config time. That way, they can run in parallel, and this pattern means that # config time. That way, they can run in parallel, and this pattern means that
# e.g. creating the clang config header (which happens in another gn file) # e.g. creating the clang config header (which happens in another gn file)
@ -19,6 +20,9 @@ import("//llvm/version.gni")
# Other than in the cmake build, header generation doesn't do any feature # Other than in the cmake build, header generation doesn't do any feature
# checking. See also "Philosophy" in llvm/utils/gn/README.rst. # checking. See also "Philosophy" in llvm/utils/gn/README.rst.
##############################################################################
# config.h, llvm-config.h, abi-breaking.h
# FIXME: Several of the config settings go in a global config header but # FIXME: Several of the config settings go in a global config header but
# are only used in a single translation unit -- so toggling that value # are only used in a single translation unit -- so toggling that value
# causes a full rebuild when it really only has to rebuild a single file. # causes a full rebuild when it really only has to rebuild a single file.
@ -356,3 +360,71 @@ action("llvm-config") {
args += [ "LLVM_ENABLE_THREADS=" ] args += [ "LLVM_ENABLE_THREADS=" ]
} }
} }
##############################################################################
# .def files used by llvm/lib/Target
template("write_target_def_file") {
assert(defined(invoker.key), "callers must set key")
assert(defined(invoker.value), "callers must set value")
action(target_name) {
visibility = [ ":write_target_def_files" ]
script = "//llvm/utils/gn/build/write_cmake_config.py"
sources = [
"$target_name.in",
]
outputs = [
"$target_gen_dir/$target_name",
]
# Build something like
# `LLVM_ENUM_ASM_PARSERS=LLVM_ASM_PARSER(ARM)\nLLVM_ASM_PARSER(X86)\n`. Note
# that \n is a literal '\' followed by a literal 'n', not a newline
# character. (write_cmake_config.py replaces that with a real newline).
value = ""
foreach(target, llvm_targets_to_build) {
value = "$value${invoker.value}($target)\n"
}
args = [
"-o",
rebase_path(outputs[0], root_out_dir),
rebase_path(sources[0], root_out_dir),
"${invoker.key}=$value",
]
}
}
write_target_def_file("AsmParsers.def") {
key = "LLVM_ENUM_ASM_PARSERS"
value = "LLVM_ASM_PARSER"
}
write_target_def_file("AsmPrinters.def") {
key = "LLVM_ENUM_ASM_PRINTERS"
value = "LLVM_ASM_PRINTER"
}
write_target_def_file("Disassemblers.def") {
key = "LLVM_ENUM_DISASSEMBLERS"
value = "LLVM_DISASSEMBLER"
}
write_target_def_file("Targets.def") {
key = "LLVM_ENUM_TARGETS"
value = "LLVM_TARGET"
}
group("write_target_def_files") {
visibility = [
"//llvm/lib/Support",
"//llvm/lib/Target",
]
deps = [
":AsmParsers.def",
":AsmPrinters.def",
":Disassemblers.def",
":Targets.def",
]
}

View File

@ -19,6 +19,8 @@ static_library("Support") {
# both Support and ADT. # both Support and ADT.
"//llvm/include/llvm/Config:abi-breaking", "//llvm/include/llvm/Config:abi-breaking",
"//llvm/include/llvm/Config:llvm-config", "//llvm/include/llvm/Config:llvm-config",
# public_dep because public header TargetSelect.h includes these .def files.
"//llvm/include/llvm/Config:write_target_def_files",
] ]
include_dirs = [ include_dirs = [
"Unix", "Unix",

View File

@ -0,0 +1,26 @@
import("//llvm/lib/Target/targets.gni")
static_library("Target") {
output_name = "LLVMTarget"
deps = [
"//llvm/lib/Analysis",
"//llvm/lib/IR",
"//llvm/lib/MC",
"//llvm/lib/Support",
]
public_deps = [
# This is a bit of a hack: llvm-c/Target.h includes llvm/Config/Targets.def,
# but there's no target corresponding to llvm-c. Since the functions
# declared in llvm-c/Target.h are defined in llvm/lib/Target, clients of
# it must depend on llvm/lib/Target, so add the public_dep for Targets.def
# here.
"//llvm/include/llvm/Config:write_target_def_files",
]
sources = [
"Target.cpp",
"TargetIntrinsicInfo.cpp",
"TargetLoweringObjectFile.cpp",
"TargetMachine.cpp",
"TargetMachineC.cpp",
]
}