[Lldb-commits] [lldb] Reland "[lldb][headers] Create Python script to fix up framework head… (PR #143945)
Chelsea Cassanova via lldb-commits
lldb-commits at lists.llvm.org
Thu Jun 12 11:12:52 PDT 2025
https://github.com/chelcassanova updated https://github.com/llvm/llvm-project/pull/143945
>From 4f873a3ee458009541a7015cfa63a247bc792737 Mon Sep 17 00:00:00 2001
From: Chelsea Cassanova <chelsea_cassanova at apple.com>
Date: Thu, 12 Jun 2025 10:46:36 -0700
Subject: [PATCH] Reland "[lldb][headers] Create Python script to fix up
framework headers" (#143941)
Reland the script that converts lldb headers to RPC headers. The RPC
test was failing due to the incorrect input filepath being used.
---
lldb/cmake/modules/LLDBFramework.cmake | 42 +++---
lldb/scripts/framework-header-fix.py | 126 ++++++++++++++++++
.../Shell/Scripts/Inputs/Main/SBAddress.h | 13 ++
.../Shell/Scripts/Inputs/RPC/RPCSBAddress.h | 9 ++
.../Shell/Scripts/TestFrameworkFixScript.test | 11 ++
.../Scripts/TestFrameworkFixUnifdef.test | 12 ++
.../Scripts/TestRPCFrameworkFixScript.test | 14 ++
7 files changed, 206 insertions(+), 21 deletions(-)
create mode 100755 lldb/scripts/framework-header-fix.py
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/TestFrameworkFixUnifdef.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 8961b1afe93ad..70010ffbf738c 100644
--- a/lldb/cmake/modules/LLDBFramework.cmake
+++ b/lldb/cmake/modules/LLDBFramework.cmake
@@ -68,24 +68,17 @@ 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 will 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")
+file(GLOB lldb_build_dir_header_staging_list ${lldb_build_dir_header_staging}/*)
+foreach(header ${lldb_build_dir_header_staging_list})
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.
@@ -112,13 +105,20 @@ set_target_properties(liblldb-resource-headers PROPERTIES FOLDER "LLDB/Resources
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).
-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"
-)
+# 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.
+file(GLOB lldb_framework_header_staging_list ${lldb_framework_header_staging}/*)
+foreach(header ${lldb_framework_header_staging_list})
+
+ set(input_header ${header})
+ set(output_header $<TARGET_FILE_DIR:liblldb>/Headers/${input_header})
+
+ add_custom_command(TARGET liblldb POST_BUILD
+ COMMAND ${LLDB_SOURCE_DIR}/scripts/framework-header-fix.py -f lldb_main -i ${input_header} -o ${output_header} -p ${unifdef_EXECUTABLE} USWIG
+ COMMENT "LLDB.framework: Fix up and copy framework headers"
+ )
+endforeach()
# Copy vendor-specific headers from clang (without staging).
if(NOT APPLE_EMBEDDED)
diff --git a/lldb/scripts/framework-header-fix.py b/lldb/scripts/framework-header-fix.py
new file mode 100755
index 0000000000000..9e4e5f860a2c0
--- /dev/null
+++ b/lldb/scripts/framework-header-fix.py
@@ -0,0 +1,126 @@
+#!/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(1)
+
+ 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]
+
+ 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()
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..e90c3bdfc5adb
--- /dev/null
+++ b/lldb/test/Shell/Scripts/TestFrameworkFixScript.test
@@ -0,0 +1,11 @@
+# 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 -f lldb_main -i %p/Inputs/Main/SBAddress.h -o %t/Outputs/SBAddress.h -p /usr/bin/unifdef 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>
diff --git a/lldb/test/Shell/Scripts/TestFrameworkFixUnifdef.test b/lldb/test/Shell/Scripts/TestFrameworkFixUnifdef.test
new file mode 100644
index 0000000000000..a7e82d2f3640c
--- /dev/null
+++ b/lldb/test/Shell/Scripts/TestFrameworkFixUnifdef.test
@@ -0,0 +1,12 @@
+# REQUIRES: system-darwin
+# 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 -f lldb_main -i %p/Inputs/Main/SBAddress.h -o %t/Outputs/SBAddress.h -p /usr/bin/unifdef USWIG
+
+# Check the output
+RUN: cat %t/Outputs/SBAddress.h | FileCheck %s
+
+# 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..d015942653967
--- /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 -f lldb_rpc -i %p/Inputs/RPC/RPCSBAddress.h -o %t/Outputs/RPCSBAddress.h -p /usr/bin/unifdef USWIG
+
+# 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/LLDBRPC.h>
+CHECK: #include <LLDBRPC/SBDefines.h>
+CHECK: #include <LLDBRPC/RPCPublic.h>
More information about the lldb-commits
mailing list