-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfix_includes.py
More file actions
145 lines (116 loc) · 4.66 KB
/
Copy pathfix_includes.py
File metadata and controls
145 lines (116 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import os
import sys
import yaml
SETTINGS_FILE = "fix_includes.yaml"
class ParseInfo:
def __init__(self, path="", do_cmake=True, do_includes=False):
self.path = path
self.do_cmake = do_cmake
self.do_includes = do_includes
class Settings:
def __init__(self, parse_infos=None):
self.parse_infos = parse_infos or [ParseInfo()]
def load_settings(settings_file: str) -> Settings:
if not os.path.exists(settings_file):
# Create default settings file
settings = Settings()
with open(settings_file, "w") as f:
yaml.dump(settings.__dict__, f, sort_keys=False)
return settings
else:
with open(settings_file, "r") as f:
data = yaml.safe_load(f)
parse_infos = [
ParseInfo(
path=item.get("path", ""),
do_cmake=item.get("doCMAKE", True),
do_includes=item.get("doIncludes", False)
)
for item in data.get("parseInfos", [])
]
print("Loaded Settings:")
print(yaml.dump(data, sort_keys=False))
return Settings(parse_infos)
def create_include_file(path: str, indent: int = 0):
folder_name = os.path.basename(path)
include_file = os.path.join(path, f"{folder_name}.h")
with open(include_file, "w") as out:
out.write("#pragma once\n\n")
prefix = f"{' ' * (indent * 2)}{folder_name}"
print(f"{prefix}{' ' * max(1, 20 - len(prefix))}( ", end="")
for file in os.listdir(path):
if file.endswith(".h") and file != f"{folder_name}.h":
out.write(f'#include "{file}"\n')
print(f"{file} ", end="")
out.write("\n")
print(")")
for subdir in [d for d in os.listdir(path) if os.path.isdir(os.path.join(path, d))]:
out.write(f'#include "{subdir}/{subdir}.h"\n')
create_include_file(os.path.join(path, subdir), indent + 1)
def create_set_block_sources(path: str) -> str:
files = []
for root, _, filenames in os.walk(path):
for f in filenames:
if f.endswith((".c", ".cpp")):
rel_path = os.path.relpath(os.path.join(root, f), path).replace("\\", "/")
files.append(f' "{rel_path}"')
return "set(SOURCE_FILES_LIST\n" + "\n".join(files) + "\n)"
def create_set_block_includes(path: str) -> str:
dirs = []
for root, subdirs, _ in os.walk(path):
for d in subdirs:
rel = os.path.relpath(os.path.join(root, d), path).replace("\\", "/")
dirs.append(f' "{rel}"')
return "set(INCLUDE_DIRS_LIST\n .\n" + "\n".join(dirs) + "\n)"
def build_default_cmake_file(path: str) -> str:
return f"""# This file is automatically generated by FixIncludes tool.
{create_set_block_sources(path)}
{create_set_block_includes(path)}
# Register component with ESP-IDF
idf_component_register()
# Apply source files and include directories
target_sources(${{COMPONENT_LIB}} PRIVATE ${{SOURCE_FILES_LIST}})
target_include_directories(${{COMPONENT_LIB}} PRIVATE ${{INCLUDE_DIRS_LIST}})
"""
def replace_set_block(content: str, block_name: str, replacement: str) -> str:
start = content.find(f"set({block_name}")
if start == -1:
return content
end = content.find(")", start)
if end == -1:
return content
end = content.find("\n", end)
if end == -1:
end = len(content)
return content[:start] + replacement + content[end:]
def fix_cmake_file(path: str):
file_path = os.path.join(path, "CMakeLists.txt")
original = ""
if os.path.exists(file_path):
with open(file_path, "r") as f:
original = f.read()
has_source = "set(SOURCE_FILES_LIST" in original
has_include = "set(INCLUDE_DIRS_LIST" in original
has_register = "idf_component_register(" in original
if not (has_source and has_include and has_register):
with open(file_path, "w") as f:
f.write(build_default_cmake_file(path))
return
updated = replace_set_block(original, "SOURCE_FILES_LIST", create_set_block_sources(path))
updated = replace_set_block(updated, "INCLUDE_DIRS_LIST", create_set_block_includes(path))
with open(file_path, "w") as f:
f.write(updated)
def process_settings(settings: Settings):
for item in settings.parse_infos:
full_path = os.path.abspath(item.path)
if item.do_includes:
create_include_file(full_path)
if item.do_cmake:
fix_cmake_file(full_path)
print()
def main():
settings = load_settings(SETTINGS_FILE)
print("\nProcessing library header files and CMakeLists...\n")
process_settings(settings)
if __name__ == "__main__":
main()