135 lines · python
1#!/usr/bin/env python32 3"""4Usage: <path/to/input-directory> <path/to/output-directory>5 6This script is used when building LLDB.framework or LLDBRPC.framework. For each framework, local includes are converted to their respective framework includes.7 8This script is used in 2 ways:91. 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>.10 112. 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>12"""13 14import argparse15import os16import re17import shutil18import subprocess19import sys20 21# Main header regexes22INCLUDE_FILENAME_REGEX = re.compile(23 r'#include "lldb/(API/)?(?P<include_filename>.*){0,1}"'24)25 26# RPC header regexes27RPC_COMMON_REGEX = re.compile(r"#include <lldb-rpc/common/(?P<include_filename>.*)>")28RPC_INCLUDE_FILENAME_REGEX = re.compile(r'#include "(?P<include_filename>.*)"')29 30 31def modify_rpc_includes(input_file_path, output_file_path):32 with open(input_file_path, "r") as input_file:33 lines = input_file.readlines()34 file_buffer = "".join(lines)35 with open(output_file_path, "w") as output_file:36 # Local includes must be changed to RPC framework level includes.37 # e.g. #include "SBDefines.h" -> #include <LLDBRPC/SBDefines.h>38 # Also, RPC common code includes must change to RPC framework level includes.39 # e.g. #include "lldb-rpc/common/RPCPublic.h" -> #include <LLDBRPC/RPCPublic.h>40 rpc_common_matches = RPC_COMMON_REGEX.finditer(file_buffer)41 rpc_include_filename_matches = RPC_INCLUDE_FILENAME_REGEX.finditer(42 file_buffer43 )44 for match in rpc_common_matches:45 file_buffer = re.sub(46 match.group(),47 r"#include <LLDBRPC/" + match.group("include_filename") + ">",48 file_buffer,49 )50 for match in rpc_include_filename_matches:51 file_buffer = re.sub(52 match.group(),53 r"#include <LLDBRPC/" + match.group("include_filename") + ">",54 file_buffer,55 )56 output_file.write(file_buffer)57 58 59def modify_main_includes(input_file_path, output_file_path):60 with open(input_file_path, "r") as input_file:61 lines = input_file.readlines()62 file_buffer = "".join(lines)63 with open(output_file_path, "w") as output_file:64 # Local includes must be changed to framework level includes.65 # e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h>66 regex_matches = INCLUDE_FILENAME_REGEX.finditer(file_buffer)67 for match in regex_matches:68 file_buffer = re.sub(69 match.group(),70 r"#include <LLDB/" + match.group("include_filename") + ">",71 file_buffer,72 )73 output_file.write(file_buffer)74 75 76def remove_guards(output_file_path, unifdef_path, unifdef_guards):77 # The unifdef path should be passed in from CMake. If it wasn't there in CMake or is incorrect,78 # find it using shutil. If shutil can't find it, then exit.79 if not shutil.which(unifdef_path):80 unifdef_path = shutil.which("unifdef")81 if not unifdef_path:82 print(83 "Unable to find unifdef executable. Guards will not be removed from input files. Exiting..."84 )85 sys.exit()86 87 subprocess_command = (88 [unifdef_path, "-o", output_file_path] + unifdef_guards + [output_file_path]89 )90 subprocess.run(subprocess_command)91 92 93def main():94 parser = argparse.ArgumentParser()95 parser.add_argument("-f", "--framework", choices=["lldb_main", "lldb_rpc"])96 parser.add_argument("-i", "--input_file")97 parser.add_argument("-o", "--output_file")98 parser.add_argument("-p", "--unifdef_path")99 parser.add_argument(100 "--unifdef_guards",101 nargs="+",102 type=str,103 help="Guards to be removed with unifdef. These must be specified in the same way as they would be when passed directly into unifdef.",104 )105 args = parser.parse_args()106 input_file_path = str(args.input_file)107 output_file_path = str(args.output_file)108 framework_version = args.framework109 unifdef_path = str(args.unifdef_path)110 # Prepend dashes to the list of guards passed in from the command line.111 # unifdef takes the guards to remove as arguments in their own right (e.g. -USWIG)112 # but passing them in with dashes for this script causes argparse to think that they're113 # arguments in and of themself, so they need to passed in without dashes.114 if args.unifdef_guards:115 unifdef_guards = ["-U" + guard for guard in args.unifdef_guards]116 117 # Create the framework's header dir if it doesn't already exist118 try:119 os.makedirs(os.path.dirname(output_file_path))120 except FileExistsError:121 pass122 123 if framework_version == "lldb_main":124 modify_main_includes(input_file_path, output_file_path)125 if framework_version == "lldb_rpc":126 modify_rpc_includes(input_file_path, output_file_path)127 # After the incldues have been modified, run unifdef on the headers to remove any guards128 # specified at the command line.129 if args.unifdef_guards:130 remove_guards(output_file_path, unifdef_path, unifdef_guards)131 132 133if __name__ == "__main__":134 main()135