• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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