]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/build_tools/amalgamate.py
2 # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
4 # amalgamate.py creates an amalgamation from a unity build.
5 # It can be run with either Python 2 or 3.
6 # An amalgamation consists of a header that includes the contents of all public
7 # headers and a source file that includes the contents of all source files and
10 # This script works by starting with the unity build file and recursively expanding
11 # #include directives. If the #include is found in a public include directory,
12 # that header is expanded into the amalgamation header.
14 # A particular header is only expanded once, so this script will
15 # break if there are multiple inclusions of the same header that are expected to
16 # expand differently. Similarly, this type of code causes issues:
22 # #include "bar.h" // oops, doesn't get expanded
23 # // different code here
26 # The solution is to move the include out of the #ifdef.
28 from __future__
import print_function
35 include_re
= re
.compile('^[ \t]*#include[ \t]+"(.*)"[ \t]*$')
39 def find_header(name
, abs_path
, include_paths
):
40 samedir
= path
.join(path
.dirname(abs_path
), name
)
41 if path
.exists(samedir
):
43 for include_path
in include_paths
:
44 include_path
= path
.join(include_path
, name
)
45 if path
.exists(include_path
):
49 def expand_include(include_path
, f
, abs_path
, source_out
, header_out
, include_paths
, public_include_paths
):
50 if include_path
in included
:
53 included
.add(include_path
)
54 with
open(include_path
) as f
:
55 print('#line 1 "{}"'.format(include_path
), file=source_out
)
56 process_file(f
, include_path
, source_out
, header_out
, include_paths
, public_include_paths
)
59 def process_file(f
, abs_path
, source_out
, header_out
, include_paths
, public_include_paths
):
60 for (line
, text
) in enumerate(f
):
61 m
= include_re
.match(text
)
63 filename
= m
.groups()[0]
64 # first check private headers
65 include_path
= find_header(filename
, abs_path
, include_paths
)
67 if include_path
in excluded
:
68 source_out
.write(text
)
71 expanded
= expand_include(include_path
, f
, abs_path
, source_out
, header_out
, include_paths
, public_include_paths
)
73 # now try public headers
74 include_path
= find_header(filename
, abs_path
, public_include_paths
)
78 if include_path
in excluded
:
79 source_out
.write(text
)
81 expand_include(include_path
, f
, abs_path
, header_out
, None, public_include_paths
, [])
83 sys
.exit("unable to find {}, included in {} on line {}".format(filename
, abs_path
, line
))
86 print('#line {} "{}"'.format(line
+1, abs_path
), file=source_out
)
87 elif text
!= "#pragma once\n":
88 source_out
.write(text
)
91 parser
= argparse
.ArgumentParser(description
="Transform a unity build into an amalgamation")
92 parser
.add_argument("source", help="source file")
93 parser
.add_argument("-I", action
="append", dest
="include_paths", help="include paths for private headers")
94 parser
.add_argument("-i", action
="append", dest
="public_include_paths", help="include paths for public headers")
95 parser
.add_argument("-x", action
="append", dest
="excluded", help="excluded header files")
96 parser
.add_argument("-o", dest
="source_out", help="output C++ file", required
=True)
97 parser
.add_argument("-H", dest
="header_out", help="output C++ header file", required
=True)
98 args
= parser
.parse_args()
100 include_paths
= list(map(path
.abspath
, args
.include_paths
or []))
101 public_include_paths
= list(map(path
.abspath
, args
.public_include_paths
or []))
102 excluded
.update(map(path
.abspath
, args
.excluded
or []))
103 filename
= args
.source
104 abs_path
= path
.abspath(filename
)
105 with
open(filename
) as f
, open(args
.source_out
, 'w') as source_out
, open(args
.header_out
, 'w') as header_out
:
106 print('#line 1 "{}"'.format(filename
), file=source_out
)
107 print('#include "{}"'.format(header_out
.name
), file=source_out
)
108 process_file(f
, abs_path
, source_out
, header_out
, include_paths
, public_include_paths
)
110 if __name__
== "__main__":