aboutsummaryrefslogtreecommitdiff
path: root/tools/cppmerge
diff options
context:
space:
mode:
author杨宇千 <crupest@outlook.com>2018-11-13 17:18:18 +0800
committerGitHub <noreply@github.com>2018-11-13 17:18:18 +0800
commit91dda866a0919f9e6cfb5e7857ac0466572d96d8 (patch)
treec3b5fc6afeb4dad0de65212d1dae38940706a58a /tools/cppmerge
parent92bec65a76b62bbbee56b44c3020171606bb8bbb (diff)
parent97c35edea2ca67a06ba66f124b94ea62f0519def (diff)
downloadcru-91dda866a0919f9e6cfb5e7857ac0466572d96d8.tar.gz
cru-91dda866a0919f9e6cfb5e7857ac0466572d96d8.tar.bz2
cru-91dda866a0919f9e6cfb5e7857ac0466572d96d8.zip
Merge pull request #17 from crupest/cppmerge-init
Add c++ source merge tools.
Diffstat (limited to 'tools/cppmerge')
-rw-r--r--tools/cppmerge/.gitignore147
-rw-r--r--tools/cppmerge/.vscode/launch.json20
-rw-r--r--tools/cppmerge/main.py160
3 files changed, 327 insertions, 0 deletions
diff --git a/tools/cppmerge/.gitignore b/tools/cppmerge/.gitignore
new file mode 100644
index 00000000..0b6b38d0
--- /dev/null
+++ b/tools/cppmerge/.gitignore
@@ -0,0 +1,147 @@
+
+# Created by https://www.gitignore.io/api/python,visualstudiocode
+# Edit at https://www.gitignore.io/?templates=python,visualstudiocode
+
+### Python ###
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+### Python Patch ###
+.venv/
+
+### Python.VirtualEnv Stack ###
+# Virtualenv
+# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
+[Bb]in
+[Ii]nclude
+[Ll]ib
+[Ll]ib64
+[Ll]ocal
+[Ss]cripts
+pyvenv.cfg
+pip-selfcheck.json
+
+### VisualStudioCode ###
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+### VisualStudioCode Patch ###
+# Ignore all local history of files
+.history
+
+# End of https://www.gitignore.io/api/python,visualstudiocode
diff --git a/tools/cppmerge/.vscode/launch.json b/tools/cppmerge/.vscode/launch.json
new file mode 100644
index 00000000..dcbc3389
--- /dev/null
+++ b/tools/cppmerge/.vscode/launch.json
@@ -0,0 +1,20 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Python",
+ "type": "python",
+ "request": "launch",
+ "program": "${workspaceFolder}/main.py",
+ "args": [
+ "--output",
+ "cru_ui",
+ "../../src"
+ ],
+ "console": "integratedTerminal"
+ }
+ ]
+} \ No newline at end of file
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!")