Add initial support for API versioning (see #3836)

- Generated files are now created when running cef_create_projects or
  the new version_manager.py tool. These files are still created in the
  cef/ source tree (same location as before) but Git ignores them due to
  the generated .gitignore file.
- API hashes are committed to Git as a new cef_api_versions.json file.
  This file is used for both code generation and CEF version calculation
  (replacing the previous usage of cef_api_hash.h for this purpose).
  It will be updated by the CEF admin before merging breaking API
  changes upstream.
- As an added benefit to the above, contributor PRs will no longer
  contain generated code that is susceptible to frequent merge conflicts.
- From a code generation perspective, the main difference is that we now
  use versioned structs (e.g. cef_browser_0_t instead of cef_browser_t)
  on the libcef (dll/framework) side. Most of the make_*.py tool changes
  are related to supporting this.
- From the client perspective, you can now define CEF_API_VERSION in the
  project configuration (or get CEF_EXPERIMENTAL by default). This
  define will change the API exposed in CEF’s include/ and include/capi
  header files. All client-side targets including libcef_dll_wrapper
  will need be recompiled when changing this define.
- Examples of the new API-related define usage are provided in
  cef_api_version_test.h, api_version_test_impl.cc and
  api_version_unittest.cc.

To test:
- Run `ceftests --gtest_filter=ApiVersionTest.*`
- Add `cef_api_version=13300` to GN_DEFINES. Re-run configure, build and
  ceftests steps.
- Repeat with 13301, 13302, 13303 (all supported test versions).
This commit is contained in:
Marshall Greenblatt
2024-12-09 15:20:44 -05:00
parent 219bf3406c
commit dd81904a2f
68 changed files with 7466 additions and 1265 deletions

View File

@@ -4,6 +4,7 @@
from __future__ import absolute_import
from cef_parser import *
import functools
def make_ctocpp_impl_proto(clsname, name, func, parts):
@@ -25,42 +26,31 @@ def make_ctocpp_impl_proto(clsname, name, func, parts):
return proto
def make_ctocpp_function_impl_existing(clsname, name, func, impl):
notify(name + ' has manual edits')
def make_ctocpp_function_impl_existing(cls, name, func, impl, version):
clsname = None if cls is None else cls.get_name(version=version)
notify_name = name if clsname is None else '%sCToCpp::%s' % (clsname, name)
notify(notify_name + ' has manual edits')
# retrieve the C++ prototype parts
parts = func.get_cpp_parts(True)
changes = format_translation_changes(impl, parts)
if len(changes) > 0:
notify(name + ' prototype changed')
notify(notify_name + ' prototype changed')
return make_ctocpp_impl_proto(clsname, name, func, parts)+'{'+ \
changes+impl['body']+'\n}\n\n'
changes+impl['body']+'\n}\n'
def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
def make_ctocpp_function_impl_new(cls, name, func, base_scoped, version,
version_finder):
# Special handling for the CefShutdown global function.
is_cef_shutdown = name == 'CefShutdown' and isinstance(
func.parent, obj_header)
# build the C++ prototype
parts = func.get_cpp_parts(True)
result = make_ctocpp_impl_proto(clsname, name, func, parts) + ' {'
if isinstance(func.parent, obj_class) and \
not func.parent.has_attrib('no_debugct_check') and \
not base_scoped:
result += '\n shutdown_checker::AssertNotShutdown();\n'
if isinstance(func, obj_function_virtual):
# determine how the struct should be referenced
if clsname == func.parent.get_name():
result += '\n ' + get_capi_name(clsname,
True) + '* _struct = GetStruct();'
else:
result += '\n '+func.parent.get_capi_name()+'* _struct = reinterpret_cast<'+\
func.parent.get_capi_name()+'*>(GetStruct());'
clsname = None if cls is None else cls.get_name(version=version)
notify_name = name if clsname is None else '%sCToCpp::%s' % (clsname, name)
invalid = []
@@ -83,23 +73,43 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
if len(retval_default) > 0:
retval_default = ' ' + retval_default
# build the C++ prototype
parts = func.get_cpp_parts(True)
result = make_ctocpp_impl_proto(clsname, name, func, parts) + ' {'
is_virtual = isinstance(func, obj_function_virtual)
if is_virtual and not version is None and not func.exists_at_version(version):
notreached = format_notreached(
True,
'" should not be called at version %d"' % version,
default_retval=retval_default.strip())
result += '\n // AUTO-GENERATED CONTENT' + \
'\n ' + notreached + \
'\n}\n'
return result
if isinstance(func.parent, obj_class) and \
not func.parent.has_attrib('no_debugct_check') and \
not base_scoped:
result += '\n shutdown_checker::AssertNotShutdown();\n'
if is_virtual:
# determine how the struct should be referenced
if cls.get_name() == func.parent.get_name():
result += '\n auto* _struct = GetStruct();'
else:
result += '\n auto* _struct = reinterpret_cast<'+\
func.parent.get_capi_name(version=version)+'*>(GetStruct());'
# add API hash check
if func.has_attrib('api_hash_check'):
result += '\n const char* api_hash = cef_api_hash(0);'\
'\n if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {'\
'\n // The libcef API hash does not match the current header API hash.'\
'\n DCHECK(false);'\
'\n return'+retval_default+';'\
'\n }\n'
if isinstance(func, obj_function_virtual):
# add the structure size check
result += '\n if (CEF_MEMBER_MISSING(_struct, ' + func.get_capi_name() + ')) {'\
'\n return' + retval_default + ';\n'\
'\n }\n'
result += '\n const char* api_hash = cef_api_hash(CEF_API_VERSION, 0);'\
'\n CHECK(!strcmp(api_hash, CEF_API_HASH_PLATFORM)) <<'\
'\n "API hashes for libcef and libcef_dll_wrapper do not match.";\n'
if len(invalid) > 0:
notify(name + ' could not be autogenerated')
notify(notify_name + ' could not be autogenerated')
# code could not be auto-generated
result += '\n // BEGIN DELETE BEFORE MODIFYING'
result += '\n // AUTO-GENERATED CONTENT'
@@ -209,38 +219,39 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
params.append(arg_name + '.GetWritableStruct()')
elif arg_type == 'refptr_same':
ptr_class = arg.get_type().get_ptr_type()
params.append(ptr_class + 'CToCpp::Unwrap(' + arg_name + ')')
params.append(ptr_class + 'CToCpp_Unwrap(' + arg_name + ')')
elif arg_type == 'ownptr_same':
ptr_class = arg.get_type().get_ptr_type()
params.append(ptr_class + 'CToCpp::UnwrapOwn(std::move(' + arg_name +
'))')
params.append(ptr_class + 'CToCpp_UnwrapOwn(std::move(' + arg_name + '))')
elif arg_type == 'rawptr_same':
ptr_class = arg.get_type().get_ptr_type()
params.append(ptr_class + 'CToCpp::UnwrapRaw(' + arg_name + ')')
params.append(ptr_class + 'CToCpp_UnwrapRaw(' + arg_name + ')')
elif arg_type == 'refptr_diff':
ptr_class = arg.get_type().get_ptr_type()
params.append(ptr_class + 'CppToC::Wrap(' + arg_name + ')')
params.append(ptr_class + 'CppToC_Wrap(' + arg_name + ')')
elif arg_type == 'ownptr_diff':
ptr_class = arg.get_type().get_ptr_type()
params.append(ptr_class + 'CppToC::WrapOwn(std::move(' + arg_name + '))')
params.append(ptr_class + 'CppToC_WrapOwn(std::move(' + arg_name + '))')
elif arg_type == 'rawptr_diff':
ptr_class = arg.get_type().get_ptr_type()
result += comment+\
'\n CefOwnPtr<'+ptr_class+'CppToC> '+arg_name+'Ptr('+ptr_class+'CppToC::WrapRaw('+arg_name+'));'
params.append(arg_name + 'Ptr->GetStruct()')
'\n auto ['+arg_name+'Ptr, '+arg_name+'Struct] = '+ptr_class+'CppToC_WrapRaw('+arg_name+');'
params.append(arg_name + 'Struct')
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
ptr_struct = arg.get_type().get_result_ptr_type_root()
if not version_finder is None:
ptr_struct = version_finder(ptr_struct)
if arg_type == 'refptr_same_byref':
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + ')'
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + ')'
else:
assign = ptr_class + 'CppToC::Wrap(' + arg_name + ')'
assign = ptr_class + 'CppToC_Wrap(' + arg_name + ')'
result += comment+\
'\n '+ptr_struct+'* '+arg_name+'Struct = NULL;'\
'\n if ('+arg_name+'.get()) {'\
'\n '+arg_name+'Struct = '+assign+';'\
'\n }'\
'\n '+ptr_struct+'* '+arg_name+'Orig = '+arg_name+'Struct;'
'\n auto* '+arg_name+'Orig = '+arg_name+'Struct;'
params.append('&' + arg_name + 'Struct')
elif arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const':
result += comment+\
@@ -270,12 +281,15 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
count_func = arg.get_attrib_count_func()
vec_type = arg.get_type().get_result_vector_type_root()
if not version_finder is None:
vec_type = version_finder(vec_type)
if arg_type == 'refptr_vec_same_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + '[i])'
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + '[i])'
elif arg_type == 'refptr_vec_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CppToC::Wrap(' + arg_name + '[i])'
assign = ptr_class + 'CppToC_Wrap(' + arg_name + '[i])'
else:
assign = arg_name + '[i]'
result += comment+\
@@ -301,18 +315,21 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
count_func = arg.get_attrib_count_func()
vec_type = arg.get_type().get_result_vector_type_root()
if not version_finder is None:
vec_type = version_finder(vec_type)
if arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const':
assign = arg_name + '[i]'
else:
ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'refptr_vec_same_byref_const':
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + '[i])'
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + '[i])'
elif arg_type == 'refptr_vec_diff_byref_const':
assign = ptr_class + 'CppToC::Wrap(' + arg_name + '[i])'
assign = ptr_class + 'CppToC_Wrap(' + arg_name + '[i])'
elif arg_type == 'rawptr_vec_same_byref_const':
assign = ptr_class + 'CToCpp::UnwrapRaw(' + arg_name + '[i])'
assign = ptr_class + 'CToCpp_UnwrapRaw(' + arg_name + '[i])'
elif arg_type == 'rawptr_vec_diff_byref_const':
assign = ptr_class + 'CppToC::WrapRaw(' + arg_name + '[i]).release()->GetStruct()'
assign = ptr_class + 'CppToC_WrapRawAndRelease(' + arg_name + '[i])'
result += comment+\
'\n const size_t '+arg_name+'Count = '+arg_name+'.size();'\
'\n '+vec_type+'* '+arg_name+'List = NULL;'\
@@ -348,8 +365,7 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
result += 'cef_string_userfree_t'
elif retval_type == 'refptr_same' or retval_type == 'refptr_diff' or \
retval_type == 'ownptr_same' or retval_type == 'ownptr_diff':
ptr_struct = retval.get_type().get_result_ptr_type_root()
result += ptr_struct + '*'
result += 'auto*'
else:
raise Exception('Unsupported return type %s in %s' % (retval_type, name))
@@ -390,11 +406,10 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
'\n }'
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
ptr_struct = arg.get_type().get_result_ptr_type_root()
if arg_type == 'refptr_same_byref':
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + 'Struct)'
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + 'Struct)'
else:
assign = ptr_class + 'CppToC::Unwrap(' + arg_name + 'Struct)'
assign = ptr_class + 'CppToC_Unwrap(' + arg_name + 'Struct)'
result += comment+\
'\n if ('+arg_name+'Struct) {'\
'\n if ('+arg_name+'Struct != '+arg_name+'Orig) {'\
@@ -442,13 +457,13 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
count_func = arg.get_attrib_count_func()
vec_type = arg.get_type().get_result_vector_type_root()
if arg_type == 'refptr_vec_same_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + 'List[i])'
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + 'List[i])'
elif arg_type == 'refptr_vec_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CppToC::Unwrap(' + arg_name + 'List[i])'
assign = ptr_class + 'CppToC_Unwrap(' + arg_name + 'List[i])'
elif arg_type == 'bool_vec_byref':
assign = arg_name + 'List[i]?true:false'
else:
@@ -468,7 +483,7 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
if arg_type == 'rawptr_vec_diff_byref_const':
result += '\n if ('+arg_name+'Count > 0) {'\
'\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
'\n delete '+ptr_class+'CppToC::GetWrapper('+arg_name+'List[i]);'\
'\n delete '+ptr_class+'CppToC_GetWrapper('+arg_name+'List[i]);'\
'\n }'\
'\n }'
result += '\n if ('+arg_name+'List) {'\
@@ -497,43 +512,59 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
'\n return _retvalStr;'
elif retval_type == 'refptr_same' or retval_type == 'ownptr_same':
ptr_class = retval.get_type().get_ptr_type()
result += '\n return ' + ptr_class + 'CToCpp::Wrap(_retval);'
result += '\n return ' + ptr_class + 'CToCpp_Wrap(_retval);'
elif retval_type == 'refptr_diff':
ptr_class = retval.get_type().get_ptr_type()
result += '\n return ' + ptr_class + 'CppToC::Unwrap(_retval);'
result += '\n return ' + ptr_class + 'CppToC_Unwrap(_retval);'
elif retval_type == 'ownptr_diff':
ptr_class = retval.get_type().get_ptr_type()
result += '\n return ' + ptr_class + 'CppToC::UnwrapOwn(_retval);'
result += '\n return ' + ptr_class + 'CppToC_UnwrapOwn(_retval);'
else:
raise Exception('Unsupported return type %s in %s' % (retval_type, name))
if len(result) != result_len:
result += '\n'
result += '}\n\n'
result += '}\n'
return result
def make_ctocpp_function_impl(clsname, funcs, existing, base_scoped):
def make_ctocpp_function_impl(cls, funcs, existing, base_scoped, version,
version_finder):
impl = ''
customized = False
for func in funcs:
name = func.get_name()
value = get_next_function_impl(existing, name)
if version is None:
pre, post = get_version_surround(func, long=True)
else:
pre = post = ''
if not value is None \
and value['body'].find('// AUTO-GENERATED CONTENT') < 0:
# an implementation exists that was not auto-generated
impl += make_ctocpp_function_impl_existing(clsname, name, func, value)
customized = True
impl += pre + make_ctocpp_function_impl_existing(cls, name, func, value,
version) + post + '\n'
else:
impl += make_ctocpp_function_impl_new(clsname, name, func, base_scoped)
impl += pre + make_ctocpp_function_impl_new(
cls, name, func, base_scoped, version, version_finder) + post + '\n'
return impl
if not customized and impl.find('// COULD NOT IMPLEMENT') >= 0:
customized = True
return (impl, customized)
def make_ctocpp_virtual_function_impl(header, cls, existing, base_scoped):
impl = make_ctocpp_function_impl(cls.get_name(),
cls.get_virtual_funcs(), existing,
base_scoped)
def make_ctocpp_virtual_function_impl(header, cls, existing, base_scoped,
version, version_finder):
impl, customized = make_ctocpp_function_impl(
cls,
cls.get_virtual_funcs(), existing, base_scoped, version, version_finder)
cur_cls = cls
while True:
@@ -544,18 +575,28 @@ def make_ctocpp_virtual_function_impl(header, cls, existing, base_scoped):
parent_cls = header.get_class(parent_name)
if parent_cls is None:
raise Exception('Class does not exist: ' + parent_name)
impl += make_ctocpp_function_impl(cls.get_name(),
parent_cls.get_virtual_funcs(),
existing, base_scoped)
pimpl, pcustomized = make_ctocpp_function_impl(
cls,
parent_cls.get_virtual_funcs(), existing, base_scoped, version,
version_finder)
impl += pimpl
if pcustomized and not customized:
customized = True
cur_cls = header.get_class(parent_name)
return impl
return (impl, customized)
def make_ctocpp_unwrap_derived(header, cls, base_scoped):
def make_ctocpp_unwrap_derived(header, cls, base_scoped, version):
# identify all classes that derive from cls
derived_classes = []
clsname = cls.get_name()
if version is None:
capiname = cls.get_capi_name()
else:
capiname = cls.get_capi_name(version=version)
allclasses = header.get_classes()
for cur_cls in allclasses:
if cur_cls.get_name() == clsname:
@@ -568,34 +609,156 @@ def make_ctocpp_unwrap_derived(header, cls, base_scoped):
if base_scoped:
impl = ['', '']
for clsname in derived_classes:
impl[0] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
clsname+'CToCpp::UnwrapOwn(CefOwnPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c.release()))));\n'+\
' }\n'
impl[1] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
clsname+'CToCpp::UnwrapRaw(CefRawPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c))));\n'+\
' }\n'
derived_cls = header.get_class(clsname)
if version is None:
pre, post = get_version_surround(derived_cls)
else:
if not derived_cls.exists_at_version(version):
continue
pre = post = ''
impl[0] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+capiname+'*>('+\
clsname+'CToCpp_UnwrapOwn(CefOwnPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c.release()))));\n'+\
' }\n' + post
impl[1] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+capiname+'*>('+\
clsname+'CToCpp_UnwrapRaw(CefRawPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c))));\n'+\
' }\n' + post
else:
impl = ''
for clsname in derived_classes:
impl += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
clsname+'CToCpp::Unwrap(reinterpret_cast<'+clsname+'*>(c)));\n'+\
' }\n'
derived_cls = header.get_class(clsname)
if version is None:
pre, post = get_version_surround(derived_cls)
else:
if not derived_cls.exists_at_version(version):
continue
pre = post = ''
impl += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+capiname+'*>('+\
clsname+'CToCpp_Unwrap(reinterpret_cast<'+clsname+'*>(c)));\n'+\
' }\n' + post
return impl
def make_ctocpp_version_wrappers(header, cls, base_scoped, versions):
assert len(versions) > 0
clsname = cls.get_name()
typename = clsname + 'CToCpp'
structname = cls.get_capi_name(version=versions[0])
rversions = sorted(versions, reverse=True)
notreached = format_notreached(
True,
'" called with invalid version " << version',
default_retval='nullptr')
impl = ''
if base_scoped:
impl += 'CefOwnPtr<' + clsname + '> ' + typename + '_Wrap(' + structname + '* s) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::Wrap(s);\n'
else:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::Wrap(reinterpret_cast<' + cls.get_capi_name(
version) + '*>(s));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
structname + '* ' + typename + '_UnwrapOwn(CefOwnPtr<' + clsname + '> c) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::UnwrapOwn(std::move(c));\n'
else:
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CToCpp::UnwrapOwn(std::move(c)));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
structname + '* ' + typename + '_UnwrapRaw(CefRawPtr<' + clsname + '> c) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::UnwrapRaw(std::move(c));\n'
else:
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CToCpp::UnwrapRaw(std::move(c)));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n'
else:
impl += 'CefRefPtr<' + clsname + '> ' + typename + '_Wrap(' + structname + '* s) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::Wrap(s);\n'
else:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::Wrap(reinterpret_cast<' + cls.get_capi_name(
version) + '*>(s));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
structname + '* ' + typename + '_Unwrap(CefRefPtr<' + clsname + '> c) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::Unwrap(c);\n'
else:
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CToCpp::Unwrap(c));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n'
return impl + '\n'
def _version_finder(header, version, name):
assert version is None or isinstance(version, int), version
# normalize ptr values
if name[-1] == '*':
name = name[0:-1]
suffix = '*'
else:
suffix = ''
cls = header.get_capi_class(name)
if not cls is None:
name = cls.get_capi_name(first_version=True)
return name + suffix
def make_ctocpp_class_impl(header, clsname, impl):
cls = header.get_class(clsname)
if cls is None:
raise Exception('Class does not exist: ' + clsname)
capiname = cls.get_capi_name()
# retrieve the existing virtual function implementations
existing = get_function_impls(impl, clsname + 'CToCpp::')
base_class_name = header.get_base_class_name(clsname)
base_scoped = True if base_class_name == 'CefBaseScoped' else False
if base_scoped:
@@ -603,75 +766,135 @@ def make_ctocpp_class_impl(header, clsname, impl):
else:
template_class = 'CefCToCppRefCounted'
# generate virtual functions
virtualimpl = make_ctocpp_virtual_function_impl(header, cls, existing,
base_scoped)
if len(virtualimpl) > 0:
virtualimpl = '\n// VIRTUAL METHODS - Body may be edited by hand.\n\n' + virtualimpl
with_versions = cls.is_client_side()
versions = list(cls.get_all_versions()) if with_versions else (None,)
# retrieve the existing static function implementations
existing = get_function_impls(impl, clsname + '::')
existing_static = get_function_impls(impl, clsname + '::')
# generate static functions
staticimpl = make_ctocpp_function_impl(clsname,
cls.get_static_funcs(), existing,
base_scoped)
if len(staticimpl) > 0:
staticimpl = '\n// STATIC METHODS - Body may be edited by hand.\n\n' + staticimpl
staticout = virtualout = ''
customized = False
first = True
idx = 0
resultingimpl = staticimpl + virtualimpl
for version in versions:
version_finder = functools.partial(_version_finder, header,
version) if with_versions else None
# any derived classes can be unwrapped
unwrapderived = make_ctocpp_unwrap_derived(header, cls, base_scoped)
if first:
first = False
const = '// CONSTRUCTOR - Do not edit by hand.\n\n'+ \
clsname+'CToCpp::'+clsname+'CToCpp() {\n'+ \
'}\n\n'+ \
'// DESTRUCTOR - Do not edit by hand.\n\n'+ \
clsname+'CToCpp::~'+clsname+'CToCpp() {\n'
# generate static functions
staticimpl, scustomized = make_ctocpp_function_impl(
cls,
cls.get_static_funcs(), existing_static, base_scoped, version,
version_finder)
if len(staticimpl) > 0:
staticout += '\n// STATIC METHODS - Body may be edited by hand.\n\n' + staticimpl
if scustomized:
customized = True
if not cls.has_attrib('no_debugct_check') and not base_scoped:
const += ' shutdown_checker::AssertNotShutdown();\n'
if len(versions) > 1:
staticout += '// HELPER FUNCTIONS - Do not edit by hand.\n\n'
staticout += make_ctocpp_version_wrappers(header, cls, base_scoped,
versions)
const += '}\n\n'
comment = '' if version is None else (' FOR VERSION %d' % version)
typename = cls.get_name(version=version) + 'CToCpp'
# retrieve the existing virtual function implementations
existing_virtual = get_function_impls(impl, typename + '::')
# generate virtual functions
virtualimpl, vcustomized = make_ctocpp_virtual_function_impl(
header, cls, existing_virtual, base_scoped, version, version_finder)
if len(virtualimpl) > 0:
virtualout += '\n// VIRTUAL METHODS' + comment + ' - Body may be edited by hand.\n\n' + virtualimpl
if vcustomized:
customized = True
# any derived classes can be unwrapped
unwrapderived = make_ctocpp_unwrap_derived(header, cls, base_scoped,
version)
capiname = cls.get_capi_name(version=version)
const = '// CONSTRUCTOR' + comment + ' - Do not edit by hand.\n\n'+ \
typename+'::'+typename+'() {\n'
if not version is None:
if idx < len(versions) - 1:
condition = 'version < %d || version >= %d' % (version, versions[idx
+ 1])
else:
condition = 'version < %d' % version
const += ' const int version = cef_api_version();\n' + \
' LOG_IF(FATAL, ' + condition + ') << __func__ << " called with invalid version " << version;\n'
const += '}\n\n'+ \
'// DESTRUCTOR' + comment + ' - Do not edit by hand.\n\n'+ \
typename+'::~'+typename+'() {\n'
if not cls.has_attrib('no_debugct_check') and not base_scoped:
const += ' shutdown_checker::AssertNotShutdown();\n'
const += '}\n\n'
parent_sig = template_class + '<' + typename + ', ' + clsname + ', ' + capiname + '>'
notreached = format_notreached(
with_versions,
'" called with unexpected class type " << type',
default_retval='nullptr')
if base_scoped:
const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, CefOwnPtr<'+clsname+'> c) {\n'+ \
unwrapderived[0] + \
' ' + notreached + '\n'+ \
'}\n\n' + \
'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, CefRawPtr<'+clsname+'> c) {\n'+ \
unwrapderived[1] + \
' ' + notreached + '\n'+ \
'}\n\n'
else:
const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+clsname+'* c) {\n'+ \
unwrapderived + \
' ' + notreached + '\n'+ \
'}\n\n'
const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum(
clsname) + ';\n\n'
virtualout += const
idx += 1
out = staticout + virtualout
# determine what includes are required by identifying what translation
# classes are being used
includes = format_translation_includes(header, const + resultingimpl +
(unwrapderived[0]
if base_scoped else unwrapderived))
includes = format_translation_includes(
header,
out + (unwrapderived[0] if base_scoped else unwrapderived),
with_versions=with_versions)
# build the final output
result = get_copyright()
result += includes + '\n' + resultingimpl + '\n'
result += includes + '\n'
parent_sig = template_class + '<' + clsname + 'CToCpp, ' + clsname + ', ' + capiname + '>'
if base_scoped:
const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, CefOwnPtr<'+clsname+'> c) {\n'+ \
unwrapderived[0] + \
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
' return nullptr;\n'+ \
'}\n\n' + \
'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, CefRawPtr<'+clsname+'> c) {\n'+ \
unwrapderived[1] + \
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
' return nullptr;\n'+ \
'}\n\n'
if with_versions:
pre = post = ''
else:
const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+clsname+'* c) {\n'+ \
unwrapderived + \
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
' return nullptr;\n'+ \
'}\n\n'
pre, post = get_version_surround(cls, long=True)
if len(pre) > 0:
result += pre + '\n'
const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum(
clsname) + ';'
result += out + '\n'
result += const
if len(post) > 0:
result += post + '\n'
return result
return (result, customized)
def make_ctocpp_global_impl(header, impl):
@@ -679,31 +902,31 @@ def make_ctocpp_global_impl(header, impl):
existing = get_function_impls(impl, 'CEF_GLOBAL')
# generate static functions
impl = make_ctocpp_function_impl(None, header.get_funcs(), existing, False)
impl, customized = make_ctocpp_function_impl(None,
header.get_funcs(), existing,
False, None, None)
if len(impl) > 0:
impl = '\n// GLOBAL METHODS - Body may be edited by hand.\n\n' + impl
includes = ''
# include required headers for global functions
filenames = []
paths = set()
for func in header.get_funcs():
filename = func.get_file_name()
if not filename in filenames:
includes += '#include "include/'+func.get_file_name()+'"\n' \
'#include "include/capi/'+func.get_capi_file_name()+'"\n'
filenames.append(filename)
paths.add('include/' + func.get_file_name())
paths.add('include/capi/' + func.get_capi_file_name())
# determine what includes are required by identifying what translation
# classes are being used
includes += format_translation_includes(header, impl)
includes += format_translation_includes(header, impl, other_includes=paths)
# build the final output
result = get_copyright()
result += includes + '\n// Define used to facilitate parsing.\n#define CEF_GLOBAL\n\n' + impl
return result
return (result, customized)
def write_ctocpp_impl(header, clsname, dir):
@@ -717,16 +940,22 @@ def write_ctocpp_impl(header, clsname, dir):
dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_ctocpp.cc')
set_notify_context(file)
if path_exists(file):
oldcontents = read_file(file)
else:
oldcontents = ''
if clsname is None:
newcontents = make_ctocpp_global_impl(header, oldcontents)
newcontents, customized = make_ctocpp_global_impl(header, oldcontents)
else:
newcontents = make_ctocpp_class_impl(header, clsname, oldcontents)
return (file, newcontents)
newcontents, customized = make_ctocpp_class_impl(header, clsname,
oldcontents)
set_notify_context(None)
return (file, newcontents, customized)
# test the module