https://github.com/chelcassanova updated https://github.com/llvm/llvm-project/pull/142051
>From 7a5672078a4a60077c025ace82f18cbab88fdf3d Mon Sep 17 00:00:00 2001 From: Chelsea Cassanova <chelsea_cassan...@apple.com> Date: Wed, 28 May 2025 15:45:45 -0700 Subject: [PATCH] [lldb][headers] Create Python script to fix up framework headers This commit replaces the shell script that fixes up includes for the LLDB framework with a Python script. This script will also be used when fixing up includes for the LLDBRPC.framework. --- lldb/cmake/modules/LLDBFramework.cmake | 34 +++--- lldb/scripts/framework-header-fix.py | 110 ++++++++++++++++++ lldb/scripts/framework-header-fix.sh | 17 --- .../Shell/Scripts/Inputs/Main/SBAddress.h | 13 +++ .../Shell/Scripts/Inputs/RPC/RPCSBAddress.h | 9 ++ .../Shell/Scripts/TestFrameworkFixScript.test | 16 +++ .../Scripts/TestRPCFrameworkFixScript.test | 14 +++ 7 files changed, 177 insertions(+), 36 deletions(-) create mode 100755 lldb/scripts/framework-header-fix.py delete mode 100755 lldb/scripts/framework-header-fix.sh create mode 100644 lldb/test/Shell/Scripts/Inputs/Main/SBAddress.h create mode 100644 lldb/test/Shell/Scripts/Inputs/RPC/RPCSBAddress.h create mode 100644 lldb/test/Shell/Scripts/TestFrameworkFixScript.test create mode 100644 lldb/test/Shell/Scripts/TestRPCFrameworkFixScript.test diff --git a/lldb/cmake/modules/LLDBFramework.cmake b/lldb/cmake/modules/LLDBFramework.cmake index 471aeaaad3c0d..028bdec5bcdf3 100644 --- a/lldb/cmake/modules/LLDBFramework.cmake +++ b/lldb/cmake/modules/LLDBFramework.cmake @@ -68,24 +68,16 @@ if(NOT APPLE_EMBEDDED) ) endif() -# At configuration time, collect headers for the framework bundle and copy them -# into a staging directory. Later we can copy over the entire folder. -file(GLOB public_headers ${LLDB_SOURCE_DIR}/include/lldb/API/*.h) -set(generated_public_headers ${LLDB_OBJ_DIR}/include/lldb/API/SBLanguages.h) -file(GLOB root_public_headers ${LLDB_SOURCE_DIR}/include/lldb/lldb-*.h) -file(GLOB root_private_headers ${LLDB_SOURCE_DIR}/include/lldb/lldb-private*.h) -list(REMOVE_ITEM root_public_headers ${root_private_headers}) - find_program(unifdef_EXECUTABLE unifdef) -set(lldb_header_staging ${CMAKE_CURRENT_BINARY_DIR}/FrameworkHeaders) -foreach(header - ${public_headers} - ${generated_public_headers} - ${root_public_headers}) +# All necessary header files should be staged in the include directory in the build directory, +# so just copy the files from there into the framework's staging directory. +set(lldb_build_dir_header_staging ${CMAKE_BINARY_DIR}/include/lldb) +set(lldb_framework_header_staging ${CMAKE_CURRENT_BINARY_DIR}/FrameworkHeaders) +foreach(header ${lldb_build_dir_header_staging}) get_filename_component(basename ${header} NAME) - set(staged_header ${lldb_header_staging}/${basename}) + set(staged_header ${lldb_framework_header_staging}/${basename}) if(unifdef_EXECUTABLE) # unifdef returns 0 when the file is unchanged and 1 if something was changed. @@ -107,14 +99,18 @@ endforeach() # Wrap output in a target, so lldb-framework can depend on it. add_custom_target(liblldb-resource-headers DEPENDS lldb-sbapi-dwarf-enums ${lldb_staged_headers}) set_target_properties(liblldb-resource-headers PROPERTIES FOLDER "LLDB/Resources") + +# We're taking the header files from where they've been staged in the build directory's include folder, +# so create a dependency on the build step that creates that directory. +add_dependencies(liblldb-resource-headers liblldb-header-staging) add_dependencies(liblldb liblldb-resource-headers) -# At build time, copy the staged headers into the framework bundle (and do -# some post-processing in-place). +# Take the headers from the staging directory and fix up their includes for the framework. +# Then write them to the output directory. +# Also, run unifdef to remove any specified guards from the header files. add_custom_command(TARGET liblldb POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory ${lldb_header_staging} $<TARGET_FILE_DIR:liblldb>/Headers - COMMAND ${LLDB_SOURCE_DIR}/scripts/framework-header-fix.sh $<TARGET_FILE_DIR:liblldb>/Headers ${LLDB_VERSION} - COMMENT "LLDB.framework: copy framework headers" + COMMAND ${LLDB_SOURCE_DIR}/scripts/framework-header-fix.py lldb_main ${lldb_framework_header_staging} $<TARGET_FILE_DIR:liblldb>/Headers --unifdef_guards=-USWIG + COMMENT "LLDB.framework: Fix up and copy framework headers" ) # Copy vendor-specific headers from clang (without staging). diff --git a/lldb/scripts/framework-header-fix.py b/lldb/scripts/framework-header-fix.py new file mode 100755 index 0000000000000..0a478a577dc3c --- /dev/null +++ b/lldb/scripts/framework-header-fix.py @@ -0,0 +1,110 @@ +#!/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 + +# 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_directory_path, output_directory_path): + for input_filepath in os.listdir(input_directory_path): + current_input_file = os.path.join(input_directory_path, input_filepath) + output_dest = os.path.join(output_directory_path, input_filepath) + if os.path.isfile(current_input_file): + with open(current_input_file, "r") as input_file: + lines = input_file.readlines() + file_buffer = "".join(lines) + with open(output_dest, "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_directory_path, output_directory_path): + for input_filepath in os.listdir(input_directory_path): + current_input_file = os.path.join(input_directory_path, input_filepath) + output_dest = os.path.join(output_directory_path, input_filepath) + if os.path.isfile(current_input_file): + with open(current_input_file, "r") as input_file: + lines = input_file.readlines() + file_buffer = "".join(lines) + with open(output_dest, "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_directory_path, unifdef_guards): + unifdef_path = shutil.which("unifdef") + for current_file in os.listdir(output_directory_path): + current_file = os.path.join(output_directory_path, current_file) + subprocess_command = [unifdef_path, "-o", current_file] + unifdef_guards + [current_file] + subprocess.run(subprocess_command) + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("framework", choices=["lldb_main", "lldb_rpc"]) + parser.add_argument("input_directory") + parser.add_argument("output_directory") + parser.add_argument("--unifdef_guards", nargs="*", 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_directory_path = str(args.input_directory) + output_directory_path = str(args.output_directory) + framework_version = args.framework + unifdef_guards = args.unifdef_guards[0].split(",") + + if framework_version == "lldb_main": + modify_main_includes(input_directory_path, output_directory_path) + if framework_version == "lldb_rpc": + modify_rpc_includes(input_directory_path, output_directory_path) + # After the incldues have been modified, run unifdef on the headers to remove any guards + # specified at the command line. + remove_guards(output_directory_path, unifdef_guards) + + +if __name__ == "__main__": + main() diff --git a/lldb/scripts/framework-header-fix.sh b/lldb/scripts/framework-header-fix.sh deleted file mode 100755 index 3459dd91c9ec1..0000000000000 --- a/lldb/scripts/framework-header-fix.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -# Usage: framework-header-fix.sh <source header dir> <LLDB Version> - -set -e - -for file in `find $1 -name "*.h"` -do - /usr/bin/sed -i.bak 's/\(#include\)[ ]*"lldb\/\(API\/\)\{0,1\}\(.*\)"/\1 <LLDB\/\3>/1' "$file" - /usr/bin/sed -i.bak 's|<LLDB/Utility|<LLDB|' "$file" - LLDB_VERSION=`echo $2 | /usr/bin/sed -E 's/^([0-9]+).([0-9]+).([0-9]+)(.[0-9]+)?$/\\1/g'` - LLDB_REVISION=`echo $2 | /usr/bin/sed -E 's/^([0-9]+).([0-9]+).([0-9]+)(.[0-9]+)?$/\\3/g'` - LLDB_VERSION_STRING=`echo $2` - /usr/bin/sed -i.bak "s|//#define LLDB_VERSION$|#define LLDB_VERSION $LLDB_VERSION |" "$file" - /usr/bin/sed -i.bak "s|//#define LLDB_REVISION|#define LLDB_REVISION $LLDB_REVISION |" "$file" - /usr/bin/sed -i.bak "s|//#define LLDB_VERSION_STRING|#define LLDB_VERSION_STRING \"$LLDB_VERSION_STRING\" |" "$file" - rm -f "$file.bak" -done diff --git a/lldb/test/Shell/Scripts/Inputs/Main/SBAddress.h b/lldb/test/Shell/Scripts/Inputs/Main/SBAddress.h new file mode 100644 index 0000000000000..fecc69687cd74 --- /dev/null +++ b/lldb/test/Shell/Scripts/Inputs/Main/SBAddress.h @@ -0,0 +1,13 @@ +// This is a truncated version of an SB API file +// used to test framework-header-fix.py to make sure the includes are correctly fixed +// up for the LLDB.framework. + +// Local includes must be changed to framework level includes. +// e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h> +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBModule.h" + +// Any include guards specified at the command line must be removed. +#ifndef SWIG +int a = 10 +#endif diff --git a/lldb/test/Shell/Scripts/Inputs/RPC/RPCSBAddress.h b/lldb/test/Shell/Scripts/Inputs/RPC/RPCSBAddress.h new file mode 100644 index 0000000000000..556afa38a9225 --- /dev/null +++ b/lldb/test/Shell/Scripts/Inputs/RPC/RPCSBAddress.h @@ -0,0 +1,9 @@ +// This is a truncated version of an SB API file generated by lldb-rpc-gen +// used to test framework-header-fix.py to make sure the includes are correctly fixed +// up for the LLDBRPC.framework. + +// Local includes must be changed to framework level includes. +// e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h> +#include "LLDBRPC.h" +#include "SBDefines.h" +#include <lldb-rpc/common/RPCPublic.h> diff --git a/lldb/test/Shell/Scripts/TestFrameworkFixScript.test b/lldb/test/Shell/Scripts/TestFrameworkFixScript.test new file mode 100644 index 0000000000000..c9b848c42092a --- /dev/null +++ b/lldb/test/Shell/Scripts/TestFrameworkFixScript.test @@ -0,0 +1,16 @@ +# Create a temp dir for output and run the framework fix script on the truncated version of SBAddress.h in the inputs dir. +RUN: mkdir -p %t/Outputs +RUN: %python %p/../../../scripts/framework-header-fix.py lldb_main %p/Inputs/Main %t/Outputs/ --unifdef_guards=-USWIG + +# Check the output +RUN: cat %t/Outputs/SBAddress.h | FileCheck %s + +# Local includes must be changed to framework level includes. +# e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h> +CHECK: #include <LLDB/SBDefines.h> +CHECK: #include <LLDB/SBModule.h> + +# Any include guards specified at the command line must be removed. +CHECK-NOT: #ifndef SWIG +CHECK: int a = 10 +CHECK-NOT: #endif diff --git a/lldb/test/Shell/Scripts/TestRPCFrameworkFixScript.test b/lldb/test/Shell/Scripts/TestRPCFrameworkFixScript.test new file mode 100644 index 0000000000000..be2f70f7a2461 --- /dev/null +++ b/lldb/test/Shell/Scripts/TestRPCFrameworkFixScript.test @@ -0,0 +1,14 @@ +# Create a temp dir for output and run the framework fix script on the truncated version of SBAddress.h in the inputs dir. +RUN: mkdir -p %t/Outputs +RUN: %python %p/../../../scripts/framework-header-fix.py lldb_rpc %p/Inputs/ %t/Outputs/ + +# Check the output +RUN: cat %t/Outputs/RPCSBAddress.h | FileCheck %s + +# 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> +CHECK: #include <LLDBRPC/RPCPublic.h> +CHECK: #include <LLDBRPC/SBDefines.h> +CHECK: #include <LLDBRPC/LLDBRPC.h> _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits