Skip to content

Commit 4064ae7

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 9553514 commit 4064ae7

File tree

7 files changed

+184
-36
lines changed

7 files changed

+184
-36
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 lldb_main ${lldb_framework_header_staging} $<TARGET_FILE_DIR:liblldb>/Headers --unifdef_guards=-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: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
18+
# Main header regexes
19+
INCLUDE_FILENAME_REGEX = re.compile(
20+
r'#include "lldb/API/(?P<include_filename>.*){0,1}"'
21+
)
22+
23+
# RPC header regexes
24+
RPC_COMMON_REGEX = re.compile(r"#include <lldb-rpc/common/(?P<include_filename>.*)>")
25+
RPC_INCLUDE_FILENAME_REGEX = re.compile(r'#include "(?P<include_filename>.*)"')
26+
27+
28+
def modify_rpc_includes(input_directory_path, output_directory_path):
29+
for input_filepath in os.listdir(input_directory_path):
30+
current_input_file = os.path.join(input_directory_path, input_filepath)
31+
output_dest = os.path.join(output_directory_path, input_filepath)
32+
if os.path.isfile(current_input_file):
33+
with open(current_input_file, "r") as input_file:
34+
lines = input_file.readlines()
35+
file_buffer = "".join(lines)
36+
with open(output_dest, "w") as output_file:
37+
# Local includes must be changed to RPC framework level includes.
38+
# e.g. #include "SBDefines.h" -> #include <LLDBRPC/SBDefines.h>
39+
# Also, RPC common code includes must change to RPC framework level includes.
40+
# e.g. #include "lldb-rpc/common/RPCPublic.h" -> #include <LLDBRPC/RPCPublic.h>
41+
rpc_common_matches = RPC_COMMON_REGEX.finditer(file_buffer)
42+
rpc_include_filename_matches = RPC_INCLUDE_FILENAME_REGEX.finditer(
43+
file_buffer
44+
)
45+
for match in rpc_common_matches:
46+
file_buffer = re.sub(
47+
match.group(),
48+
r"#include <LLDBRPC/" + match.group("include_filename") + ">",
49+
file_buffer,
50+
)
51+
for match in rpc_include_filename_matches:
52+
file_buffer = re.sub(
53+
match.group(),
54+
r"#include <LLDBRPC/" + match.group("include_filename") + ">",
55+
file_buffer,
56+
)
57+
output_file.write(file_buffer)
58+
59+
60+
def modify_main_includes(input_directory_path, output_directory_path):
61+
for input_filepath in os.listdir(input_directory_path):
62+
current_input_file = os.path.join(input_directory_path, input_filepath)
63+
output_dest = os.path.join(output_directory_path, input_filepath)
64+
if os.path.isfile(current_input_file):
65+
with open(current_input_file, "r") as input_file:
66+
lines = input_file.readlines()
67+
file_buffer = "".join(lines)
68+
with open(output_dest, "w") as output_file:
69+
# Local includes must be changed to framework level includes.
70+
# e.g. #include "lldb/API/SBDefines.h" -> #include <LLDB/SBDefines.h>
71+
regex_matches = INCLUDE_FILENAME_REGEX.finditer(file_buffer)
72+
for match in regex_matches:
73+
file_buffer = re.sub(
74+
match.group(),
75+
r"#include <LLDB/" + match.group("include_filename") + ">",
76+
file_buffer,
77+
)
78+
output_file.write(file_buffer)
79+
80+
81+
def remove_guards(output_directory_path, unifdef_guards):
82+
unifdef_path = shutil.which("unifdef")
83+
for current_file in os.listdir(output_directory_path):
84+
current_file = os.path.join(output_directory_path, current_file)
85+
subprocess_command = (
86+
[unifdef_path, "-o", current_file] + unifdef_guards + [current_file]
87+
)
88+
subprocess.run(subprocess_command)
89+
90+
91+
def main():
92+
parser = argparse.ArgumentParser()
93+
parser.add_argument("framework", choices=["lldb_main", "lldb_rpc"])
94+
parser.add_argument("input_directory")
95+
parser.add_argument("output_directory")
96+
parser.add_argument(
97+
"--unifdef_guards",
98+
nargs="*",
99+
help="Guards to be removed with unifdef. These must be specified in the same way as they would be when passed directly into unifdef.",
100+
)
101+
args = parser.parse_args()
102+
input_directory_path = str(args.input_directory)
103+
output_directory_path = str(args.output_directory)
104+
framework_version = args.framework
105+
unifdef_guards = args.unifdef_guards[0].split(",")
106+
107+
if framework_version == "lldb_main":
108+
modify_main_includes(input_directory_path, output_directory_path)
109+
if framework_version == "lldb_rpc":
110+
modify_rpc_includes(input_directory_path, output_directory_path)
111+
# After the incldues have been modified, run unifdef on the headers to remove any guards
112+
# specified at the command line.
113+
remove_guards(output_directory_path, unifdef_guards)
114+
115+
116+
if __name__ == "__main__":
117+
main()

lldb/scripts/framework-header-fix.sh

Lines changed: 0 additions & 17 deletions
This file was deleted.
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)