From e6918187568dbd01842d8d1d2c808ce16a894239 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:54:28 +0200 Subject: Adding upstream version 18.2.2. Signed-off-by: Daniel Baumann --- src/rocksdb/build_tools/amalgamate.py | 168 ++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100755 src/rocksdb/build_tools/amalgamate.py (limited to 'src/rocksdb/build_tools/amalgamate.py') diff --git a/src/rocksdb/build_tools/amalgamate.py b/src/rocksdb/build_tools/amalgamate.py new file mode 100755 index 000000000..f79e9075e --- /dev/null +++ b/src/rocksdb/build_tools/amalgamate.py @@ -0,0 +1,168 @@ +#!/usr/bin/python +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + +# amalgamate.py creates an amalgamation from a unity build. +# It can be run with either Python 2 or 3. +# An amalgamation consists of a header that includes the contents of all public +# headers and a source file that includes the contents of all source files and +# private headers. +# +# This script works by starting with the unity build file and recursively expanding +# #include directives. If the #include is found in a public include directory, +# that header is expanded into the amalgamation header. +# +# A particular header is only expanded once, so this script will +# break if there are multiple inclusions of the same header that are expected to +# expand differently. Similarly, this type of code causes issues: +# +# #ifdef FOO +# #include "bar.h" +# // code here +# #else +# #include "bar.h" // oops, doesn't get expanded +# // different code here +# #endif +# +# The solution is to move the include out of the #ifdef. + +from __future__ import print_function + +import argparse +import re +import sys +from os import path + +include_re = re.compile('^[ \t]*#include[ \t]+"(.*)"[ \t]*$') +included = set() +excluded = set() + + +def find_header(name, abs_path, include_paths): + samedir = path.join(path.dirname(abs_path), name) + if path.exists(samedir): + return samedir + for include_path in include_paths: + include_path = path.join(include_path, name) + if path.exists(include_path): + return include_path + return None + + +def expand_include( + include_path, + f, + abs_path, + source_out, + header_out, + include_paths, + public_include_paths, +): + if include_path in included: + return False + + included.add(include_path) + with open(include_path) as f: + print('#line 1 "{}"'.format(include_path), file=source_out) + process_file( + f, include_path, source_out, header_out, include_paths, public_include_paths + ) + return True + + +def process_file( + f, abs_path, source_out, header_out, include_paths, public_include_paths +): + for (line, text) in enumerate(f): + m = include_re.match(text) + if m: + filename = m.groups()[0] + # first check private headers + include_path = find_header(filename, abs_path, include_paths) + if include_path: + if include_path in excluded: + source_out.write(text) + expanded = False + else: + expanded = expand_include( + include_path, + f, + abs_path, + source_out, + header_out, + include_paths, + public_include_paths, + ) + else: + # now try public headers + include_path = find_header(filename, abs_path, public_include_paths) + if include_path: + # found public header + expanded = False + if include_path in excluded: + source_out.write(text) + else: + expand_include( + include_path, + f, + abs_path, + header_out, + None, + public_include_paths, + [], + ) + else: + sys.exit( + "unable to find {}, included in {} on line {}".format( + filename, abs_path, line + ) + ) + + if expanded: + print('#line {} "{}"'.format(line + 1, abs_path), file=source_out) + elif text != "#pragma once\n": + source_out.write(text) + + +def main(): + parser = argparse.ArgumentParser( + description="Transform a unity build into an amalgamation" + ) + parser.add_argument("source", help="source file") + parser.add_argument( + "-I", + action="append", + dest="include_paths", + help="include paths for private headers", + ) + parser.add_argument( + "-i", + action="append", + dest="public_include_paths", + help="include paths for public headers", + ) + parser.add_argument( + "-x", action="append", dest="excluded", help="excluded header files" + ) + parser.add_argument("-o", dest="source_out", help="output C++ file", required=True) + parser.add_argument( + "-H", dest="header_out", help="output C++ header file", required=True + ) + args = parser.parse_args() + + include_paths = list(map(path.abspath, args.include_paths or [])) + public_include_paths = list(map(path.abspath, args.public_include_paths or [])) + excluded.update(map(path.abspath, args.excluded or [])) + filename = args.source + abs_path = path.abspath(filename) + with open(filename) as f, open(args.source_out, "w") as source_out, open( + args.header_out, "w" + ) as header_out: + print('#line 1 "{}"'.format(filename), file=source_out) + print('#include "{}"'.format(header_out.name), file=source_out) + process_file( + f, abs_path, source_out, header_out, include_paths, public_include_paths + ) + + +if __name__ == "__main__": + main() -- cgit v1.2.3