Skip to content

Commit c0079c3

Browse files
committed
[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.
1 parent 52ad274 commit c0079c3

File tree

6 files changed

+196
-19
lines changed

6 files changed

+196
-19
lines changed

lldb/cmake/modules/LLDBFramework.cmake

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -68,24 +68,16 @@ if(NOT APPLE_EMBEDDED)
6868
)
6969
endif()
7070

71-
# At configuration time, collect headers for the framework bundle and copy them
72-
# into a staging directory. Later we can copy over the entire folder.
73-
file(GLOB public_headers ${LLDB_SOURCE_DIR}/include/lldb/API/*.h)
74-
set(generated_public_headers ${LLDB_OBJ_DIR}/include/lldb/API/SBLanguages.h)
75-
file(GLOB root_public_headers ${LLDB_SOURCE_DIR}/include/lldb/lldb-*.h)
76-
file(GLOB root_private_headers ${LLDB_SOURCE_DIR}/include/lldb/lldb-private*.h)
77-
list(REMOVE_ITEM root_public_headers ${root_private_headers})
78-
7971
find_program(unifdef_EXECUTABLE unifdef)
8072

81-
set(lldb_header_staging ${CMAKE_CURRENT_BINARY_DIR}/FrameworkHeaders)
82-
foreach(header
83-
${public_headers}
84-
${generated_public_headers}
85-
${root_public_headers})
73+
# All necessary header files will be staged in the include directory in the build directory,
74+
# so just copy the files from there into the framework's staging directory.
75+
set(lldb_build_dir_header_staging ${CMAKE_BINARY_DIR}/include/lldb)
76+
set(lldb_framework_header_staging ${CMAKE_CURRENT_BINARY_DIR}/FrameworkHeaders)
77+
foreach(header ${lldb_build_dir_header_staging})
8678

8779
get_filename_component(basename ${header} NAME)
88-
set(staged_header ${lldb_header_staging}/${basename})
80+
set(staged_header ${lldb_framework_header_staging}/${basename})
8981

9082
if(unifdef_EXECUTABLE)
9183
# unifdef returns 0 when the file is unchanged and 1 if something was changed.
@@ -107,14 +99,18 @@ endforeach()
10799
# Wrap output in a target, so lldb-framework can depend on it.
108100
add_custom_target(liblldb-resource-headers DEPENDS lldb-sbapi-dwarf-enums ${lldb_staged_headers})
109101
set_target_properties(liblldb-resource-headers PROPERTIES FOLDER "LLDB/Resources")
102+
103+
# We're taking the header files from where they've been staged in the build directory's include folder,
104+
# so create a dependency on the build step that creates that directory.
105+
add_dependencies(liblldb-resource-headers liblldb-header-staging)
110106
add_dependencies(liblldb liblldb-resource-headers)
111107

112-
# At build time, copy the staged headers into the framework bundle (and do
113-
# some post-processing in-place).
108+
# Take the headers from the staging directory and fix up their includes for the framework.
109+
# Then write them to the output directory.
110+
# Also, run unifdef to remove any specified guards from the header files.
114111
add_custom_command(TARGET liblldb POST_BUILD
115-
COMMAND ${CMAKE_COMMAND} -E copy_directory ${lldb_header_staging} $<TARGET_FILE_DIR:liblldb>/Headers
116-
COMMAND ${LLDB_SOURCE_DIR}/scripts/framework-header-fix.sh $<TARGET_FILE_DIR:liblldb>/Headers ${LLDB_VERSION}
117-
COMMENT "LLDB.framework: copy framework headers"
112+
COMMAND ${LLDB_SOURCE_DIR}/scripts/framework-header-fix.py -f lldb_main -i ${lldb_framework_header_staging} -o $<TARGET_FILE_DIR:liblldb>/Headers -p ${unifdef_EXECUTABLE} USWIG
113+
COMMENT "LLDB.framework: Fix up and copy framework headers"
118114
)
119115

120116
# Copy vendor-specific headers from clang (without staging).

lldb/scripts/framework-header-fix.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
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()
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// This is a truncated version of an SB API file
2+
// used to test framework-header-fix.py to make sure the includes are correctly fixed
3+
// up for the LLDB.framework.
4+
5+
// Local includes must be changed to framework level includes.
6+
// e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h>
7+
#include "lldb/API/SBDefines.h"
8+
#include "lldb/API/SBModule.h"
9+
10+
// Any include guards specified at the command line must be removed.
11+
#ifndef SWIG
12+
int a = 10
13+
#endif
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// This is a truncated version of an SB API file generated by lldb-rpc-gen
2+
// used to test framework-header-fix.py to make sure the includes are correctly fixed
3+
// up for the LLDBRPC.framework.
4+
5+
// Local includes must be changed to framework level includes.
6+
// e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h>
7+
#include "LLDBRPC.h"
8+
#include "SBDefines.h"
9+
#include <lldb-rpc/common/RPCPublic.h>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Create a temp dir for output and run the framework fix script on the truncated version of SBAddress.h in the inputs dir.
2+
RUN: mkdir -p %t/Outputs
3+
RUN: %python %p/../../../scripts/framework-header-fix.py lldb_main %p/Inputs/Main %t/Outputs/ --unifdef_guards=-USWIG
4+
5+
# Check the output
6+
RUN: cat %t/Outputs/SBAddress.h | FileCheck %s
7+
8+
# Local includes must be changed to framework level includes.
9+
# e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h>
10+
CHECK: #include <LLDB/SBDefines.h>
11+
CHECK: #include <LLDB/SBModule.h>
12+
13+
# Any include guards specified at the command line must be removed.
14+
CHECK-NOT: #ifndef SWIG
15+
CHECK: int a = 10
16+
CHECK-NOT: #endif
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Create a temp dir for output and run the framework fix script on the truncated version of SBAddress.h in the inputs dir.
2+
RUN: mkdir -p %t/Outputs
3+
RUN: %python %p/../../../scripts/framework-header-fix.py lldb_rpc %p/Inputs/ %t/Outputs/
4+
5+
# Check the output
6+
RUN: cat %t/Outputs/RPCSBAddress.h | FileCheck %s
7+
8+
# Local includes must be changed to RPC framework level includes.
9+
# e.g. #include "SBDefines.h" -> #include <LLDBRPC/SBDefines.h>
10+
# Also, RPC common code includes must change to RPC framework level includes.
11+
# e.g. #include "lldb-rpc/common/RPCPublic.h" -> #include <LLDBRPC/RPCPublic.h>
12+
CHECK: #include <LLDBRPC/RPCPublic.h>
13+
CHECK: #include <LLDBRPC/SBDefines.h>
14+
CHECK: #include <LLDBRPC/LLDBRPC.h>

0 commit comments

Comments
 (0)