• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2
3"""Amalgamate json-cpp library sources into a single source and header file.
4
5Works with python2.6+ and python3.4+.
6
7Example of invocation (must be invoked from json-cpp top directory):
8python amalgamate.py
9"""
10import os
11import os.path
12import sys
13
14INCLUDE_PATH = "include/json"
15SRC_PATH = "src/lib_json"
16
17class AmalgamationFile:
18    def __init__(self, top_dir):
19        self.top_dir = top_dir
20        self.blocks = []
21
22    def add_text(self, text):
23        if not text.endswith("\n"):
24            text += "\n"
25        self.blocks.append(text)
26
27    def add_file(self, relative_input_path, wrap_in_comment=False):
28        def add_marker(prefix):
29            self.add_text("")
30            self.add_text("// " + "/"*70)
31            self.add_text("// %s of content of file: %s" % (prefix, relative_input_path.replace("\\","/")))
32            self.add_text("// " + "/"*70)
33            self.add_text("")
34        add_marker("Beginning")
35        f = open(os.path.join(self.top_dir, relative_input_path), "rt")
36        content = f.read()
37        if wrap_in_comment:
38            content = "/*\n" + content + "\n*/"
39        self.add_text(content)
40        f.close()
41        add_marker("End")
42        self.add_text("\n\n\n\n")
43
44    def get_value(self):
45        return "".join(self.blocks).replace("\r\n","\n")
46
47    def write_to(self, output_path):
48        output_dir = os.path.dirname(output_path)
49        if output_dir and not os.path.isdir(output_dir):
50            os.makedirs(output_dir)
51        f = open(output_path, "wb")
52        f.write(str.encode(self.get_value(), 'UTF-8'))
53        f.close()
54
55def amalgamate_source(source_top_dir=None,
56                       target_source_path=None,
57                       header_include_path=None):
58    """Produces amalgamated source.
59       Parameters:
60           source_top_dir: top-directory
61           target_source_path: output .cpp path
62           header_include_path: generated header path relative to target_source_path.
63    """
64    print("Amalgamating header...")
65    header = AmalgamationFile(source_top_dir)
66    header.add_text("/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/).")
67    header.add_text('/// It is intended to be used with #include "%s"' % header_include_path)
68    header.add_file("LICENSE", wrap_in_comment=True)
69    header.add_text("#ifndef JSON_AMALGAMATED_H_INCLUDED")
70    header.add_text("# define JSON_AMALGAMATED_H_INCLUDED")
71    header.add_text("/// If defined, indicates that the source file is amalgamated")
72    header.add_text("/// to prevent private header inclusion.")
73    header.add_text("#define JSON_IS_AMALGAMATION")
74    header.add_file(os.path.join(INCLUDE_PATH, "version.h"))
75    header.add_file(os.path.join(INCLUDE_PATH, "allocator.h"))
76    header.add_file(os.path.join(INCLUDE_PATH, "config.h"))
77    header.add_file(os.path.join(INCLUDE_PATH, "forwards.h"))
78    header.add_file(os.path.join(INCLUDE_PATH, "json_features.h"))
79    header.add_file(os.path.join(INCLUDE_PATH, "value.h"))
80    header.add_file(os.path.join(INCLUDE_PATH, "reader.h"))
81    header.add_file(os.path.join(INCLUDE_PATH, "writer.h"))
82    header.add_file(os.path.join(INCLUDE_PATH, "assertions.h"))
83    header.add_text("#endif //ifndef JSON_AMALGAMATED_H_INCLUDED")
84
85    target_header_path = os.path.join(os.path.dirname(target_source_path), header_include_path)
86    print("Writing amalgamated header to %r" % target_header_path)
87    header.write_to(target_header_path)
88
89    base, ext = os.path.splitext(header_include_path)
90    forward_header_include_path = base + "-forwards" + ext
91    print("Amalgamating forward header...")
92    header = AmalgamationFile(source_top_dir)
93    header.add_text("/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/).")
94    header.add_text('/// It is intended to be used with #include "%s"' % forward_header_include_path)
95    header.add_text("/// This header provides forward declaration for all JsonCpp types.")
96    header.add_file("LICENSE", wrap_in_comment=True)
97    header.add_text("#ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED")
98    header.add_text("# define JSON_FORWARD_AMALGAMATED_H_INCLUDED")
99    header.add_text("/// If defined, indicates that the source file is amalgamated")
100    header.add_text("/// to prevent private header inclusion.")
101    header.add_text("#define JSON_IS_AMALGAMATION")
102    header.add_file(os.path.join(INCLUDE_PATH, "version.h"))
103    header.add_file(os.path.join(INCLUDE_PATH, "allocator.h"))
104    header.add_file(os.path.join(INCLUDE_PATH, "config.h"))
105    header.add_file(os.path.join(INCLUDE_PATH, "forwards.h"))
106    header.add_text("#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED")
107
108    target_forward_header_path = os.path.join(os.path.dirname(target_source_path),
109                                               forward_header_include_path)
110    print("Writing amalgamated forward header to %r" % target_forward_header_path)
111    header.write_to(target_forward_header_path)
112
113    print("Amalgamating source...")
114    source = AmalgamationFile(source_top_dir)
115    source.add_text("/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).")
116    source.add_text('/// It is intended to be used with #include "%s"' % header_include_path)
117    source.add_file("LICENSE", wrap_in_comment=True)
118    source.add_text("")
119    source.add_text('#include "%s"' % header_include_path)
120    source.add_text("""
121#ifndef JSON_IS_AMALGAMATION
122#error "Compile with -I PATH_TO_JSON_DIRECTORY"
123#endif
124""")
125    source.add_text("")
126    source.add_file(os.path.join(SRC_PATH, "json_tool.h"))
127    source.add_file(os.path.join(SRC_PATH, "json_reader.cpp"))
128    source.add_file(os.path.join(SRC_PATH, "json_valueiterator.inl"))
129    source.add_file(os.path.join(SRC_PATH, "json_value.cpp"))
130    source.add_file(os.path.join(SRC_PATH, "json_writer.cpp"))
131
132    print("Writing amalgamated source to %r" % target_source_path)
133    source.write_to(target_source_path)
134
135def main():
136    usage = """%prog [options]
137Generate a single amalgamated source and header file from the sources.
138"""
139    from optparse import OptionParser
140    parser = OptionParser(usage=usage)
141    parser.allow_interspersed_args = False
142    parser.add_option("-s", "--source", dest="target_source_path", action="store", default="dist/jsoncpp.cpp",
143        help="""Output .cpp source path. [Default: %default]""")
144    parser.add_option("-i", "--include", dest="header_include_path", action="store", default="json/json.h",
145        help="""Header include path. Used to include the header from the amalgamated source file. [Default: %default]""")
146    parser.add_option("-t", "--top-dir", dest="top_dir", action="store", default=os.getcwd(),
147        help="""Source top-directory. [Default: %default]""")
148    parser.enable_interspersed_args()
149    options, args = parser.parse_args()
150
151    msg = amalgamate_source(source_top_dir=options.top_dir,
152                             target_source_path=options.target_source_path,
153                             header_include_path=options.header_include_path)
154    if msg:
155        sys.stderr.write(msg + "\n")
156        sys.exit(1)
157    else:
158        print("Source successfully amalgamated")
159
160if __name__ == "__main__":
161    main()
162