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