diff options
Diffstat (limited to 'tools/cppmerge/main.py')
-rw-r--r-- | tools/cppmerge/main.py | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/tools/cppmerge/main.py b/tools/cppmerge/main.py new file mode 100644 index 00000000..6c73ff0d --- /dev/null +++ b/tools/cppmerge/main.py @@ -0,0 +1,160 @@ +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: + source_path = os.path.normpath(source_path) + 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!") |