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
|
#!/usr/bin/env python3
"""
Usage: <path/to/input-directory> <path/to/output-directory>
This script is used when building LLDB.framework or LLDBRPC.framework. For each framework, local includes are converted to their respective framework includes.
This script is used in 2 ways:
1. It is used on header files that are copied into LLDB.framework. For these files, local LLDB includes are converted into framework includes, e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h>.
2. It is used on header files for LLDBRPC.framework. For these files, includes of RPC common files will be converted to framework includes, e.g. #include <lldb-rpc/common/RPCCommon.h> -> #include <LLDBRPC/RPCCommon.h>. It will also change local includes to framework includes, e.g. #include "SBAddress.h" -> #include <LLDBRPC/SBAddress.h>
"""
import argparse
import os
import re
import shutil
import subprocess
import sys
# Main header regexes
INCLUDE_FILENAME_REGEX = re.compile(
r'#include "lldb/(API/)?(?P<include_filename>.*){0,1}"'
)
# RPC header regexes
RPC_COMMON_REGEX = re.compile(r"#include <lldb-rpc/common/(?P<include_filename>.*)>")
RPC_INCLUDE_FILENAME_REGEX = re.compile(r'#include "(?P<include_filename>.*)"')
def modify_rpc_includes(input_file_path, output_file_path):
with open(input_file_path, "r") as input_file:
lines = input_file.readlines()
file_buffer = "".join(lines)
with open(output_file_path, "w") as output_file:
# Local includes must be changed to RPC framework level includes.
# e.g. #include "SBDefines.h" -> #include <LLDBRPC/SBDefines.h>
# Also, RPC common code includes must change to RPC framework level includes.
# e.g. #include "lldb-rpc/common/RPCPublic.h" -> #include <LLDBRPC/RPCPublic.h>
rpc_common_matches = RPC_COMMON_REGEX.finditer(file_buffer)
rpc_include_filename_matches = RPC_INCLUDE_FILENAME_REGEX.finditer(
file_buffer
)
for match in rpc_common_matches:
file_buffer = re.sub(
match.group(),
r"#include <LLDBRPC/" + match.group("include_filename") + ">",
file_buffer,
)
for match in rpc_include_filename_matches:
file_buffer = re.sub(
match.group(),
r"#include <LLDBRPC/" + match.group("include_filename") + ">",
file_buffer,
)
output_file.write(file_buffer)
def modify_main_includes(input_file_path, output_file_path):
with open(input_file_path, "r") as input_file:
lines = input_file.readlines()
file_buffer = "".join(lines)
with open(output_file_path, "w") as output_file:
# Local includes must be changed to framework level includes.
# e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h>
regex_matches = INCLUDE_FILENAME_REGEX.finditer(file_buffer)
for match in regex_matches:
file_buffer = re.sub(
match.group(),
r"#include <LLDB/" + match.group("include_filename") + ">",
file_buffer,
)
output_file.write(file_buffer)
def remove_guards(output_file_path, unifdef_path, unifdef_guards):
# The unifdef path should be passed in from CMake. If it wasn't there in CMake or is incorrect,
# find it using shutil. If shutil can't find it, then exit.
if not shutil.which(unifdef_path):
unifdef_path = shutil.which("unifdef")
if not unifdef_path:
print(
"Unable to find unifdef executable. Guards will not be removed from input files. Exiting..."
)
sys.exit()
subprocess_command = (
[unifdef_path, "-o", output_file_path] + unifdef_guards + [output_file_path]
)
subprocess.run(subprocess_command)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--framework", choices=["lldb_main", "lldb_rpc"])
parser.add_argument("-i", "--input_file")
parser.add_argument("-o", "--output_file")
parser.add_argument("-p", "--unifdef_path")
parser.add_argument(
"unifdef_guards",
nargs="+",
type=str,
help="Guards to be removed with unifdef. These must be specified in the same way as they would be when passed directly into unifdef.",
)
args = parser.parse_args()
input_file_path = str(args.input_file)
output_file_path = str(args.output_file)
framework_version = args.framework
unifdef_path = str(args.unifdef_path)
# Prepend dashes to the list of guards passed in from the command line.
# unifdef takes the guards to remove as arguments in their own right (e.g. -USWIG)
# but passing them in with dashes for this script causes argparse to think that they're
# arguments in and of themself, so they need to passed in without dashes.
unifdef_guards = ["-" + guard for guard in args.unifdef_guards]
# Create the framework's header dir if it doesn't already exist
if not os.path.exists(os.path.dirname(output_file_path)):
os.makedirs(os.path.dirname(output_file_path))
if framework_version == "lldb_main":
modify_main_includes(input_file_path, output_file_path)
if framework_version == "lldb_rpc":
modify_rpc_includes(input_file_path, output_file_path)
# After the incldues have been modified, run unifdef on the headers to remove any guards
# specified at the command line.
remove_guards(output_file_path, unifdef_path, unifdef_guards)
if __name__ == "__main__":
main()
|