2025-06-12 13:55:44 -07:00
#!/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 (
2025-06-26 15:06:37 -07:00
r ' #include " lldb/(API/)?(?P<include_filename>.*) { 0,1} " '
2025-06-12 13:55:44 -07:00
)
# 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 ,
)
2025-06-26 15:06:37 -07:00
output_file . write ( file_buffer )
2025-06-12 13:55:44 -07:00
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 (
2025-07-18 15:26:09 -05:00
" --unifdef_guards " ,
2025-06-12 13:55:44 -07:00
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.
2025-07-18 15:26:09 -05:00
if args . unifdef_guards :
2025-07-30 23:04:22 -07:00
unifdef_guards = [ " -U " + guard for guard in args . unifdef_guards ]
2025-06-12 13:55:44 -07:00
2025-07-03 15:09:15 -07:00
# Create the framework's header dir if it doesn't already exist
2025-09-12 16:38:29 -07:00
try :
2025-07-03 15:09:15 -07:00
os . makedirs ( os . path . dirname ( output_file_path ) )
2025-09-12 16:38:29 -07:00
except FileExistsError :
pass
2025-07-03 15:09:15 -07:00
2025-06-12 13:55:44 -07:00
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.
2025-07-18 15:26:09 -05:00
if args . unifdef_guards :
remove_guards ( output_file_path , unifdef_path , unifdef_guards )
2025-06-12 13:55:44 -07:00
if __name__ == " __main__ " :
main ( )