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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
import argparse
import os
import os.path
import re
import sys
parser = argparse.ArgumentParser()
parser.add_argument("-o", "--output", required=True, help="The path of output header and source files excluding extension.")
parser.add_argument("input", nargs="+", help="The input source files or folders to scan.")
parser.add_argument("-e", "--exclude", nargs="+", help="Filenames that exludes from merging.")
args = parser.parse_args()
input_dirs = []
header_file_list = []
source_file_list = []
def add_source_file(path):
print("find source file: {}".format(path))
source_file_list.append(path)
def add_header_file(path):
print("find header file: {}".format(path))
header_file_list.append(path)
cpp_header_file_regex = re.compile(r"^.*\.(h|hpp)$")
cpp_source_file_regex = re.compile(r"^.*\.(cpp|cc|cxx)$")
def is_exclude(file_name):
return args.exclude and file_name in args.exclude
for path in args.input:
if os.path.isdir(path):
input_dirs.append(path)
elif os.path.isfile(path):
file_name = os.path.basename(path)
if is_exclude(file_name):
sys.exit("{} is specified excluding.")
if cpp_source_file_regex.match(file_name):
add_source_file(path)
elif cpp_header_file_regex.match(file_name):
add_header_file(path)
else:
sys.exit("{} is a file but it is neither c++ source nor header.".format(path))
else:
sys.exit("{} is neither a file nor a directory.".format(path))
actual_exclude_count = 0
for input_dir in input_dirs:
for root, subdirs, files in os.walk(input_dir):
for f in files:
if is_exclude(f):
actual_exclude_count += 1
else:
if cpp_source_file_regex.match(f):
path = os.path.join(root, f)
add_source_file(path)
elif cpp_header_file_regex.match(f):
path = os.path.join(root, f)
add_header_file(path)
print()
print("total find {} header file(s)".format(len(header_file_list)))
print("total find {} source file(s)".format(len(source_file_list)))
print("total actual exclude {} file(s)".format(actual_exclude_count))
print()
norm_source_file_list = [os.path.normpath(path) for path in source_file_list]
norm_header_file_list = [os.path.normpath(path) for path in header_file_list]
output_header_file_path = args.output + '.hpp'
output_source_file_path = args.output + '.cpp'
output_header_file = open(output_header_file_path, 'w')
output_source_file = open(output_source_file_path, 'w')
processed_headers = []
header_pragma_once_regex = re.compile(r'#\s*pragma\s*once')
header_include_command_regex = re.compile(r'#\s*include\s*"([\w.\-_/\\]+)"')
def process_line(line):
match_result = header_include_command_regex.match(line)
if match_result:
return match_result.group(1)
else:
return None
def find_header_path(base_path, header_path):
path = os.path.join(base_path, header_path)
if os.path.isfile(path):
return path
else:
for d in input_dirs:
path = os.path.join(d, header_path)
if os.path.isfile(path):
return path
raise RuntimeError("Header not found.\nBase path: {}\nHeader path: {}".format(base_path, header_path))
def process_header_file(base_path, header_path):
path = find_header_path(base_path, header_path)
path = os.path.normpath(path)
if path in processed_headers:
return
processed_headers.append(path)
output_header_file.write("//--------------------------------------------------------\n")
output_header_file.write("//-------begin of file: {}\n".format(path))
output_header_file.write("//--------------------------------------------------------\n")
header_f = open(path, 'r')
found_pragma_once = False
for line in header_f:
if (not found_pragma_once):
if header_pragma_once_regex.match(line):
found_pragma_once = True
continue
new_header_name = process_line(line)
if not new_header_name is None:
process_header_file(os.path.dirname(path), new_header_name)
else:
output_header_file.write(line)
output_header_file.write("//--------------------------------------------------------\n")
output_header_file.write("//-------end of file: {}\n".format(path))
output_header_file.write("//--------------------------------------------------------\n")
output_header_file.write("#pragma once\n")
output_source_file.write('#include "{}"\n'.format(os.path.basename(output_header_file_path)))
for source_path in source_file_list:
output_source_file.write("//--------------------------------------------------------\n")
output_source_file.write("//-------begin of file: {}\n".format(source_path))
output_source_file.write("//--------------------------------------------------------\n")
source_f = open(source_path, 'r')
for line in source_f:
new_header_name = process_line(line)
if not new_header_name is None:
process_header_file(os.path.dirname(source_path), new_header_name)
else:
output_source_file.write(line)
output_source_file.write("//--------------------------------------------------------\n")
output_source_file.write("//-------end of file: {}\n".format(source_path))
output_source_file.write("//--------------------------------------------------------\n")
rest_header_count = len(norm_header_file_list) - len(processed_headers)
if rest_header_count > 0:
print("{} header files are not included in any sources. Add them to header now.".format(rest_header_count))
print()
for header_path in norm_header_file_list:
if header_path not in processed_headers:
process_header_file('.', header_path)
print("Done!")
|