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