1# Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights 2# reserved. Use of this source code is governed by a BSD-style license that 3# can be found in the LICENSE file. 4 5from __future__ import absolute_import 6import sys 7from cef_parser import * 8from clang_util import clang_format 9from file_util import * 10import hashlib 11from make_api_hash_header import * 12from make_capi_header import * 13from make_cpptoc_header import * 14from make_cpptoc_impl import * 15from make_ctocpp_header import * 16from make_ctocpp_impl import * 17from make_gypi_file import * 18from make_libcef_dll_dylib_impl import * 19from make_views_stub_impl import * 20from make_wrapper_types_header import * 21from optparse import OptionParser 22 23# cannot be loaded as a module 24if __name__ != "__main__": 25 sys.stderr.write('This file cannot be loaded as a module!') 26 sys.exit() 27 28# parse command-line options 29disc = """ 30This utility generates files for the CEF C++ to C API translation layer. 31""" 32 33parser = OptionParser(description=disc) 34parser.add_option( 35 '--root-dir', 36 dest='rootdir', 37 metavar='DIR', 38 help='CEF root directory [required]') 39parser.add_option( 40 '--backup', 41 action='store_true', 42 dest='backup', 43 default=False, 44 help='create a backup of modified files') 45parser.add_option( 46 '--force', 47 action='store_true', 48 dest='force', 49 default=False, 50 help='force rewrite of the file') 51parser.add_option( 52 '-c', 53 '--classes', 54 dest='classes', 55 action='append', 56 help='only translate the specified classes') 57parser.add_option( 58 '-q', 59 '--quiet', 60 action='store_true', 61 dest='quiet', 62 default=False, 63 help='do not output detailed status information') 64(options, args) = parser.parse_args() 65 66# the rootdir option is required 67if options.rootdir is None: 68 parser.print_help(sys.stdout) 69 sys.exit() 70 71# determine the paths 72root_dir = os.path.abspath(options.rootdir) 73cpp_header_dir = os.path.join(root_dir, 'include') 74cpp_header_test_dir = os.path.join(cpp_header_dir, 'test') 75cpp_header_views_dir = os.path.join(cpp_header_dir, 'views') 76capi_header_dir = os.path.join(cpp_header_dir, 'capi') 77api_hash_header = os.path.join(cpp_header_dir, 'cef_api_hash.h') 78libcef_dll_dir = os.path.join(root_dir, 'libcef_dll') 79cpptoc_global_impl = os.path.join(libcef_dll_dir, 'libcef_dll.cc') 80ctocpp_global_impl = os.path.join(libcef_dll_dir, 'wrapper', 81 'libcef_dll_wrapper.cc') 82wrapper_types_header = os.path.join(libcef_dll_dir, 'wrapper_types.h') 83cpptoc_dir = os.path.join(libcef_dll_dir, 'cpptoc') 84ctocpp_dir = os.path.join(libcef_dll_dir, 'ctocpp') 85gypi_file = os.path.join(root_dir, 'cef_paths.gypi') 86views_stub_impl = os.path.join(libcef_dll_dir, 'views_stub.cc') 87libcef_dll_dylib_impl = os.path.join(libcef_dll_dir, 'wrapper', 88 'libcef_dll_dylib.cc') 89 90# make sure the header directory exists 91if not path_exists(cpp_header_dir): 92 sys.stderr.write('Directory ' + cpp_header_dir + ' does not exist.') 93 sys.exit() 94 95# create the header object 96if not options.quiet: 97 sys.stdout.write('Parsing C++ headers from ' + cpp_header_dir + '...\n') 98header = obj_header() 99 100# add include files to be processed 101header.set_root_directory(cpp_header_dir) 102excluded_files = ['cef_api_hash.h', 'cef_application_mac.h', 'cef_version.h'] 103header.add_directory(cpp_header_dir, excluded_files) 104header.add_directory(cpp_header_test_dir) 105header.add_directory(cpp_header_views_dir) 106 107# Track the number of files that were written. 108writect = 0 109 110 111def update_file(file, newcontents): 112 """ Replaces the contents of |file| with |newcontents| if necessary. """ 113 oldcontents = '' 114 oldhash = '' 115 116 if newcontents[-1:] != "\n": 117 # Add newline at end of file. 118 newcontents += "\n" 119 120 # clang-format is slow so we don't want to apply it if the pre-formatted 121 # content hasn't changed. To check for changes we embed a hash of the pre- 122 # formatted content in the resulting file. 123 hash_start = "$hash=" 124 hash_end = "$" 125 hash_token = "$$HASH$$" 126 127 if not options.force and path_exists(file): 128 oldcontents = read_file(file) 129 130 # Extract the existing hash. 131 start = oldcontents.find(hash_start) 132 if start > 0: 133 end = oldcontents.find(hash_end, start + len(hash_start)) 134 if end > 0: 135 oldhash = oldcontents[start + len(hash_start):end] 136 137 # Compute the new hash. 138 newhash = hashlib.sha1(newcontents.encode('utf-8')).hexdigest() 139 140 if oldhash == newhash: 141 # Pre-formatted contents have not changed. 142 return 143 144 newcontents = newcontents.replace(hash_token, newhash, 1) 145 146 # Apply clang-format for C/C++ files. 147 if os.path.splitext(file)[1][1:] in ('c', 'cc', 'cpp', 'h'): 148 result = clang_format(file, newcontents) 149 if result != None: 150 newcontents = result 151 else: 152 raise Exception("Call to clang-format failed") 153 154 if options.backup and oldcontents != '': 155 backup_file(file) 156 157 filedir = os.path.split(file)[0] 158 if not os.path.isdir(filedir): 159 make_dir(filedir) 160 161 write_file(file, newcontents) 162 163 global writect 164 writect += 1 165 166 167# output the C API header 168if not options.quiet: 169 sys.stdout.write('In C API header directory ' + capi_header_dir + '...\n') 170filenames = sorted(header.get_file_names()) 171for filename in filenames: 172 if not options.quiet: 173 sys.stdout.write('Generating ' + filename + ' C API header...\n') 174 update_file(*write_capi_header(header, capi_header_dir, filename)) 175 176# output the wrapper types header 177if not options.quiet: 178 sys.stdout.write('Generating wrapper types header...\n') 179update_file(*write_wrapper_types_header(header, wrapper_types_header)) 180 181# build the list of classes to parse 182allclasses = header.get_class_names() 183if not options.classes is None: 184 for cls in options.classes: 185 if not cls in allclasses: 186 sys.stderr.write('ERROR: Unknown class: ' + cls) 187 sys.exit() 188 classes = options.classes 189else: 190 classes = allclasses 191 192classes = sorted(classes) 193 194# output CppToC global file 195if not options.quiet: 196 sys.stdout.write('Generating CppToC global implementation...\n') 197update_file(*write_cpptoc_impl(header, None, cpptoc_global_impl)) 198 199# output CToCpp global file 200if not options.quiet: 201 sys.stdout.write('Generating CToCpp global implementation...\n') 202update_file(*write_ctocpp_impl(header, None, ctocpp_global_impl)) 203 204# output CppToC class files 205if not options.quiet: 206 sys.stdout.write('In CppToC directory ' + cpptoc_dir + '...\n') 207for cls in classes: 208 if not options.quiet: 209 sys.stdout.write('Generating ' + cls + 'CppToC class header...\n') 210 update_file(*write_cpptoc_header(header, cls, cpptoc_dir)) 211 if not options.quiet: 212 sys.stdout.write('Generating ' + cls + 'CppToC class implementation...\n') 213 update_file(*write_cpptoc_impl(header, cls, cpptoc_dir)) 214 215# output CppToC class files 216if not options.quiet: 217 sys.stdout.write('In CToCpp directory ' + ctocpp_dir + '...\n') 218for cls in classes: 219 if not options.quiet: 220 sys.stdout.write('Generating ' + cls + 'CToCpp class header...\n') 221 update_file(*write_ctocpp_header(header, cls, ctocpp_dir)) 222 if not options.quiet: 223 sys.stdout.write('Generating ' + cls + 'CToCpp class implementation...\n') 224 update_file(*write_ctocpp_impl(header, cls, ctocpp_dir)) 225 226# output the gypi file 227if not options.quiet: 228 sys.stdout.write('Generating ' + gypi_file + ' file...\n') 229update_file(*write_gypi_file(header, gypi_file)) 230 231# output the views stub file 232if not options.quiet: 233 sys.stdout.write('Generating ' + views_stub_impl + ' file...\n') 234update_file(*write_views_stub_impl(header, views_stub_impl)) 235 236# output the libcef dll dylib file 237if not options.quiet: 238 sys.stdout.write('Generating ' + libcef_dll_dylib_impl + ' file...\n') 239update_file(*write_libcef_dll_dylib_impl(header, libcef_dll_dylib_impl)) 240 241# Update the API hash header file if necessary. This must be done last because 242# it reads files that were potentially written by proceeding operations. 243if not options.quiet: 244 sys.stdout.write('Generating API hash header...\n') 245if write_api_hash_header(api_hash_header, cpp_header_dir): 246 writect += 1 247 248if not options.quiet: 249 sys.stdout.write('Done - Wrote ' + str(writect) + ' files.\n') 250