# Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights # reserved. Use of this source code is governed by a BSD-style license that # can be found in the LICENSE file. from __future__ import absolute_import import sys from cef_parser import * from clang_util import clang_format from file_util import * import hashlib from make_api_hash_header import * from make_capi_header import * from make_cpptoc_header import * from make_cpptoc_impl import * from make_ctocpp_header import * from make_ctocpp_impl import * from make_gypi_file import * from make_libcef_dll_dylib_impl import * from make_views_stub_impl import * from make_wrapper_types_header import * from optparse import OptionParser # cannot be loaded as a module if __name__ != "__main__": sys.stderr.write('This file cannot be loaded as a module!') sys.exit() # parse command-line options disc = """ This utility generates files for the CEF C++ to C API translation layer. """ parser = OptionParser(description=disc) parser.add_option( '--root-dir', dest='rootdir', metavar='DIR', help='CEF root directory [required]') parser.add_option( '--backup', action='store_true', dest='backup', default=False, help='create a backup of modified files') parser.add_option( '--force', action='store_true', dest='force', default=False, help='force rewrite of the file') parser.add_option( '-c', '--classes', dest='classes', action='append', help='only translate the specified classes') parser.add_option( '-q', '--quiet', action='store_true', dest='quiet', default=False, help='do not output detailed status information') (options, args) = parser.parse_args() # the rootdir option is required if options.rootdir is None: parser.print_help(sys.stdout) sys.exit() # determine the paths root_dir = os.path.abspath(options.rootdir) cpp_header_dir = os.path.join(root_dir, 'include') cpp_header_test_dir = os.path.join(cpp_header_dir, 'test') cpp_header_views_dir = os.path.join(cpp_header_dir, 'views') capi_header_dir = os.path.join(cpp_header_dir, 'capi') api_hash_header = os.path.join(cpp_header_dir, 'cef_api_hash.h') libcef_dll_dir = os.path.join(root_dir, 'libcef_dll') cpptoc_global_impl = os.path.join(libcef_dll_dir, 'libcef_dll.cc') ctocpp_global_impl = os.path.join(libcef_dll_dir, 'wrapper', 'libcef_dll_wrapper.cc') wrapper_types_header = os.path.join(libcef_dll_dir, 'wrapper_types.h') cpptoc_dir = os.path.join(libcef_dll_dir, 'cpptoc') ctocpp_dir = os.path.join(libcef_dll_dir, 'ctocpp') gypi_file = os.path.join(root_dir, 'cef_paths.gypi') views_stub_impl = os.path.join(libcef_dll_dir, 'views_stub.cc') libcef_dll_dylib_impl = os.path.join(libcef_dll_dir, 'wrapper', 'libcef_dll_dylib.cc') # make sure the header directory exists if not path_exists(cpp_header_dir): sys.stderr.write('Directory ' + cpp_header_dir + ' does not exist.') sys.exit() # create the header object if not options.quiet: sys.stdout.write('Parsing C++ headers from ' + cpp_header_dir + '...\n') header = obj_header() # add include files to be processed header.set_root_directory(cpp_header_dir) excluded_files = ['cef_api_hash.h', 'cef_application_mac.h', 'cef_version.h'] header.add_directory(cpp_header_dir, excluded_files) header.add_directory(cpp_header_test_dir) header.add_directory(cpp_header_views_dir) # Track the number of files that were written. writect = 0 def update_file(file, newcontents): """ Replaces the contents of |file| with |newcontents| if necessary. """ oldcontents = '' oldhash = '' if newcontents[-1:] != "\n": # Add newline at end of file. newcontents += "\n" # clang-format is slow so we don't want to apply it if the pre-formatted # content hasn't changed. To check for changes we embed a hash of the pre- # formatted content in the resulting file. hash_start = "$hash=" hash_end = "$" hash_token = "$$HASH$$" if not options.force and path_exists(file): oldcontents = read_file(file) # Extract the existing hash. start = oldcontents.find(hash_start) if start > 0: end = oldcontents.find(hash_end, start + len(hash_start)) if end > 0: oldhash = oldcontents[start + len(hash_start):end] # Compute the new hash. newhash = hashlib.sha1(newcontents.encode('utf-8')).hexdigest() if oldhash == newhash: # Pre-formatted contents have not changed. return newcontents = newcontents.replace(hash_token, newhash, 1) # Apply clang-format for C/C++ files. if os.path.splitext(file)[1][1:] in ('c', 'cc', 'cpp', 'h'): result = clang_format(file, newcontents) if result != None: newcontents = result else: raise Exception("Call to clang-format failed") if options.backup and oldcontents != '': backup_file(file) filedir = os.path.split(file)[0] if not os.path.isdir(filedir): make_dir(filedir) write_file(file, newcontents) global writect writect += 1 # output the C API header if not options.quiet: sys.stdout.write('In C API header directory ' + capi_header_dir + '...\n') filenames = sorted(header.get_file_names()) for filename in filenames: if not options.quiet: sys.stdout.write('Generating ' + filename + ' C API header...\n') update_file(*write_capi_header(header, capi_header_dir, filename)) # output the wrapper types header if not options.quiet: sys.stdout.write('Generating wrapper types header...\n') update_file(*write_wrapper_types_header(header, wrapper_types_header)) # build the list of classes to parse allclasses = header.get_class_names() if not options.classes is None: for cls in options.classes: if not cls in allclasses: sys.stderr.write('ERROR: Unknown class: ' + cls) sys.exit() classes = options.classes else: classes = allclasses classes = sorted(classes) # output CppToC global file if not options.quiet: sys.stdout.write('Generating CppToC global implementation...\n') update_file(*write_cpptoc_impl(header, None, cpptoc_global_impl)) # output CToCpp global file if not options.quiet: sys.stdout.write('Generating CToCpp global implementation...\n') update_file(*write_ctocpp_impl(header, None, ctocpp_global_impl)) # output CppToC class files if not options.quiet: sys.stdout.write('In CppToC directory ' + cpptoc_dir + '...\n') for cls in classes: if not options.quiet: sys.stdout.write('Generating ' + cls + 'CppToC class header...\n') update_file(*write_cpptoc_header(header, cls, cpptoc_dir)) if not options.quiet: sys.stdout.write('Generating ' + cls + 'CppToC class implementation...\n') update_file(*write_cpptoc_impl(header, cls, cpptoc_dir)) # output CppToC class files if not options.quiet: sys.stdout.write('In CToCpp directory ' + ctocpp_dir + '...\n') for cls in classes: if not options.quiet: sys.stdout.write('Generating ' + cls + 'CToCpp class header...\n') update_file(*write_ctocpp_header(header, cls, ctocpp_dir)) if not options.quiet: sys.stdout.write('Generating ' + cls + 'CToCpp class implementation...\n') update_file(*write_ctocpp_impl(header, cls, ctocpp_dir)) # output the gypi file if not options.quiet: sys.stdout.write('Generating ' + gypi_file + ' file...\n') update_file(*write_gypi_file(header, gypi_file)) # output the views stub file if not options.quiet: sys.stdout.write('Generating ' + views_stub_impl + ' file...\n') update_file(*write_views_stub_impl(header, views_stub_impl)) # output the libcef dll dylib file if not options.quiet: sys.stdout.write('Generating ' + libcef_dll_dylib_impl + ' file...\n') update_file(*write_libcef_dll_dylib_impl(header, libcef_dll_dylib_impl)) # Output the API hash header file. This must be done last because it reads files # that were potentially written by proceeding operations. if not options.quiet: sys.stdout.write('Generating API hash header...\n') update_file(*write_api_hash_header(api_hash_header, cpp_header_dir)) if not options.quiet: sys.stdout.write('Done - Wrote ' + str(writect) + ' files.\n')