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
|
#!/usr/bin/env python3
# disclaimer: this file is mostly copied from Catch2
import os
import re
import datetime
import sys
import subprocess
root_path = os.path.dirname(os.path.realpath( os.path.dirname(sys.argv[0])))
version_string = "1.0.2"
starting_header = os.path.join(root_path, 'rapidfuzz', 'rapidfuzz_all.hpp')
output_header = os.path.join(root_path, 'extras', 'rapidfuzz_amalgamated.hpp')
output_cpp = os.path.join(root_path, 'extras', 'rapidfuzz_amalgamated.cpp')
# These are the copyright comments in each file, we want to ignore them
def is_copyright_line(line):
copyright_lines = [
'/* SPDX-License-Identifier: MIT',
'/* Copyright '
]
for copyright_line in copyright_lines:
if line.startswith(copyright_line):
return True
return False
# The header of the amalgamated file: copyright information + explanation
# what this file is.
file_header = '''\
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// RapidFuzz v{version_string}
// Generated: {generation_time}
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
// ----------------------------------------------------------
'''
# Returns file header with proper version string and generation time
def formatted_file_header():
return file_header.format(version_string=version_string,
generation_time=datetime.datetime.now())
# Which headers were already concatenated (and thus should not be
# processed again)
concatenated_headers = set()
internal_include_parser = re.compile(r'\s*# *include [<"](rapidfuzz/.*)[>"].*')
def concatenate_file(out, filename: str) -> int:
# Gathers statistics on how many headers were expanded
concatenated = 1
with open(filename, mode='r', encoding='utf-8') as input:
for line in input:
if is_copyright_line(line):
continue
if line.startswith('#pragma once'):
continue
m = internal_include_parser.match(line)
# anything that isn't a RapidFuzz header can just be copied to
# the resulting file
if not m:
out.write(line)
continue
next_header = m.group(1)
# We have to avoid re-expanding the same header over and
# over again
if next_header in concatenated_headers:
continue
concatenated_headers.add(next_header)
out.write("\n")
concatenated += concatenate_file(out, os.path.join(root_path, next_header))
out.write("\n")
return concatenated
def generate_header():
with open(output_header, mode='w', encoding='utf-8') as header:
header.write(formatted_file_header())
header.write('#ifndef RAPIDFUZZ_AMALGAMATED_HPP_INCLUDED\n')
header.write('#define RAPIDFUZZ_AMALGAMATED_HPP_INCLUDED\n')
print('Concatenated {} headers'.format(concatenate_file(header, starting_header)))
header.write('#endif // RAPIDFUZZ_AMALGAMATED_HPP_INCLUDED\n')
# format output properly
subprocess.run(["clang-format", "-i", output_header])
generate_header()
# Notes:
# * For .cpp files, internal includes have to be stripped and rewritten
# * for .hpp files, internal includes have to be resolved and included
# * The .cpp file needs to start with `#include "catch_amalgamated.hpp"
# * include guards can be left/stripped, doesn't matter
# * *.cpp files should be included sorted, to minimize diffs between versions
# * *.hpp files should also be somehow sorted -> use catch_all.hpp as the
# * entrypoint
# * allow disabling main in the .cpp amalgamation
|