Skip to content

Commit 2d63dfe

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 2d63dfe

File tree

7 files changed

+210
-21
lines changed

7 files changed

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