Skip to content

Commit b8096b6

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 b8096b6

File tree

6 files changed

+202
-21
lines changed

6 files changed

+202
-21
lines changed

lldb/cmake/modules/LLDBFramework.cmake

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -68,24 +68,17 @@ 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+
file(GLOB lldb_build_dir_header_staging_list ${lldb_build_dir_header_staging}/*)
78+
foreach(header ${lldb_build_dir_header_staging_list})
8679

8780
get_filename_component(basename ${header} NAME)
88-
set(staged_header ${lldb_header_staging}/${basename})
81+
set(staged_header ${lldb_framework_header_staging}/${basename})
8982

9083
if(unifdef_EXECUTABLE)
9184
# unifdef returns 0 when the file is unchanged and 1 if something was changed.
@@ -107,15 +100,26 @@ endforeach()
107100
# Wrap output in a target, so lldb-framework can depend on it.
108101
add_custom_target(liblldb-resource-headers DEPENDS lldb-sbapi-dwarf-enums ${lldb_staged_headers})
109102
set_target_properties(liblldb-resource-headers PROPERTIES FOLDER "LLDB/Resources")
103+
104+
# We're taking the header files from where they've been staged in the build directory's include folder,
105+
# so create a dependency on the build step that creates that directory.
106+
add_dependencies(liblldb-resource-headers liblldb-header-staging)
110107
add_dependencies(liblldb liblldb-resource-headers)
111108

112-
# At build time, copy the staged headers into the framework bundle (and do
113-
# some post-processing in-place).
114-
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"
118-
)
109+
# Take the headers from the staging directory and fix up their includes for the framework.
110+
# Then write them to the output directory.
111+
# Also, run unifdef to remove any specified guards from the header files.
112+
file(GLOB lldb_framework_header_staging_list ${lldb_framework_header_staging}/*)
113+
foreach(header ${lldb_framework_header_staging_list})
114+
115+
set(input_header ${header})
116+
set(output_header $<TARGET_FILE_DIR:liblldb>/Headers/${input_header})
117+
118+
add_custom_command(TARGET liblldb POST_BUILD
119+
COMMAND ${LLDB_SOURCE_DIR}/scripts/framework-header-fix.py -f lldb_main -i ${input_header} -o ${output_header} -p ${unifdef_EXECUTABLE} USWIG
120+
COMMENT "LLDB.framework: Fix up and copy framework headers"
121+
)
122+
endforeach()
119123

120124
# Copy vendor-specific headers from clang (without staging).
121125
if(NOT APPLE_EMBEDDED)

lldb/scripts/framework-header-fix.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
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 shutil
18+
import subprocess
19+
20+
# Main header regexes
21+
INCLUDE_FILENAME_REGEX = re.compile(
22+
r'#include "lldb/API/(?P<include_filename>.*){0,1}"'
23+
)
24+
25+
# RPC header regexes
26+
RPC_COMMON_REGEX = re.compile(r"#include <lldb-rpc/common/(?P<include_filename>.*)>")
27+
RPC_INCLUDE_FILENAME_REGEX = re.compile(r'#include "(?P<include_filename>.*)"')
28+
29+
30+
def modify_rpc_includes(input_file_path, output_file_path):
31+
with open(input_file_path, "r") as input_file:
32+
lines = input_file.readlines()
33+
file_buffer = "".join(lines)
34+
with open(output_file_path, "w") as output_file:
35+
# Local includes must be changed to RPC framework level includes.
36+
# e.g. #include "SBDefines.h" -> #include <LLDBRPC/SBDefines.h>
37+
# Also, RPC common code includes must change to RPC framework level includes.
38+
# e.g. #include "lldb-rpc/common/RPCPublic.h" -> #include <LLDBRPC/RPCPublic.h>
39+
rpc_common_matches = RPC_COMMON_REGEX.finditer(file_buffer)
40+
rpc_include_filename_matches = RPC_INCLUDE_FILENAME_REGEX.finditer(
41+
file_buffer
42+
)
43+
for match in rpc_common_matches:
44+
file_buffer = re.sub(
45+
match.group(),
46+
r"#include <LLDBRPC/" + match.group("include_filename") + ">",
47+
file_buffer,
48+
)
49+
for match in rpc_include_filename_matches:
50+
file_buffer = re.sub(
51+
match.group(),
52+
r"#include <LLDBRPC/" + match.group("include_filename") + ">",
53+
file_buffer,
54+
)
55+
output_file.write(file_buffer)
56+
57+
58+
def modify_main_includes(input_file_path, output_file_path):
59+
with open(input_file_path, "r") as input_file:
60+
lines = input_file.readlines()
61+
file_buffer = "".join(lines)
62+
with open(output_file_path, "w") as output_file:
63+
# Local includes must be changed to framework level includes.
64+
# e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h>
65+
regex_matches = INCLUDE_FILENAME_REGEX.finditer(file_buffer)
66+
for match in regex_matches:
67+
file_buffer = re.sub(
68+
match.group(),
69+
r"#include <LLDB/" + match.group("include_filename") + ">",
70+
file_buffer,
71+
)
72+
output_file.write(file_buffer)
73+
74+
75+
def remove_guards(output_file_path, unifdef_path, unifdef_guards):
76+
# The unifdef path should be passed in from CMake. If it wasn't there in CMake or is incorrect,
77+
# find it using shutil. If shutil can't find it, then exit.
78+
if not shutil.which(unifdef_path):
79+
unifdef_path = shutil.which("unifdef")
80+
if not unifdef_path:
81+
print(
82+
"Unable to find unifdef executable. Guards will not be removed from input files. Exiting..."
83+
)
84+
sys.exit(1)
85+
86+
subprocess_command = (
87+
[unifdef_path, "-o", output_file_path] + unifdef_guards + [output_file_path]
88+
)
89+
subprocess.run(subprocess_command)
90+
91+
92+
def main():
93+
parser = argparse.ArgumentParser()
94+
parser.add_argument("-f", "--framework", choices=["lldb_main", "lldb_rpc"])
95+
parser.add_argument("-i", "--input_file")
96+
parser.add_argument("-o", "--output_file")
97+
parser.add_argument("-p", "--unifdef_path")
98+
parser.add_argument(
99+
"unifdef_guards",
100+
nargs="+",
101+
type=str,
102+
help="Guards to be removed with unifdef. These must be specified in the same way as they would be when passed directly into unifdef.",
103+
)
104+
args = parser.parse_args()
105+
input_file_path = str(args.input_file)
106+
output_file_path = str(args.output_file)
107+
framework_version = args.framework
108+
unifdef_path = str(args.unifdef_path)
109+
# Prepend dashes to the list of guards passed in from the command line.
110+
# unifdef takes the guards to remove as arguments in their own right (e.g. -USWIG)
111+
# but passing them in with dashes for this script causes argparse to think that they're
112+
# arguments in and of themself, so they need to passed in without dashes.
113+
unifdef_guards = ["-" + guard for guard in args.unifdef_guards]
114+
115+
if framework_version == "lldb_main":
116+
modify_main_includes(input_file_path, output_file_path)
117+
if framework_version == "lldb_rpc":
118+
modify_rpc_includes(input_file_path, output_file_path)
119+
# After the incldues have been modified, run unifdef on the headers to remove any guards
120+
# specified at the command line.
121+
remove_guards(output_file_path, unifdef_path, unifdef_guards)
122+
123+
124+
if __name__ == "__main__":
125+
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 -f lldb_main -i %p/Inputs/Main/SBAddress.h -o %t/Outputs/SBAddress.h -p /usr/bin/unifdef 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 -f lldb_rpc -i %p/Inputs/Main/RPCSBAddress.h -o %t/Outputs/RPCSBAddress.h -p /usr/bin/unifdef USWIG
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)