mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
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:
@@ -4,16 +4,16 @@
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
from clang_util import clang_eval
|
||||
from file_util import *
|
||||
import hashlib
|
||||
import itertools
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import string
|
||||
import sys
|
||||
import textwrap
|
||||
import time
|
||||
import itertools
|
||||
import hashlib
|
||||
from version_util import EXP_VERSION
|
||||
|
||||
# Determines string type for python 2 and python 3.
|
||||
if sys.version_info[0] == 3:
|
||||
@@ -22,93 +22,172 @@ else:
|
||||
string_type = basestring
|
||||
|
||||
|
||||
def _run_clang_eval(filename, content, api_version, added_defines, verbose):
|
||||
# Add a tag so we know where the header-specific output begins.
|
||||
tag = 'int begin_includes_tag;\n'
|
||||
find = '#ifdef __cplusplus\nextern "C" {'
|
||||
pos = content.find(find)
|
||||
assert pos > 0, filename
|
||||
content = content[0:pos] + tag + content[pos:]
|
||||
|
||||
defines = [
|
||||
# Makes sure CEF_EXPORT is defined.
|
||||
'USING_CEF_SHARED',
|
||||
|
||||
# Avoid include of generated headers.
|
||||
'GENERATING_CEF_API_HASH',
|
||||
]
|
||||
|
||||
if filename.find('test/') >= 0:
|
||||
# Avoids errors parsing test includes.
|
||||
defines.append('UNIT_TEST')
|
||||
|
||||
# Not the experimental version.
|
||||
api_version = int(api_version)
|
||||
if api_version != EXP_VERSION:
|
||||
# Specify the exact version.
|
||||
defines.append('CEF_API_VERSION=%d' % api_version)
|
||||
|
||||
if not added_defines is None:
|
||||
defines.extend(added_defines)
|
||||
|
||||
includes = [
|
||||
# Includes relative to the 'src/cef' directory.
|
||||
'.',
|
||||
# Includes relative to the 'src' directory.
|
||||
'..',
|
||||
]
|
||||
|
||||
result = clang_eval(
|
||||
filename,
|
||||
content,
|
||||
defines=defines,
|
||||
includes=includes,
|
||||
as_cpp=False,
|
||||
verbose=verbose)
|
||||
if result is None:
|
||||
return None
|
||||
|
||||
pos = result.find(tag)
|
||||
assert pos > 0, filename
|
||||
result = result[pos + len(tag):]
|
||||
|
||||
replacements = [
|
||||
# Undo substitutions from cef_export.h
|
||||
['__declspec(dllimport)', 'CEF_EXPORT'],
|
||||
['__attribute__((visibility("default")))', 'CEF_EXPORT'],
|
||||
['__stdcall', ''],
|
||||
]
|
||||
|
||||
for find, replace in replacements:
|
||||
result = result.replace(find, replace)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class cef_api_hash:
|
||||
""" CEF API hash calculator """
|
||||
|
||||
def __init__(self, headerdir, debugdir=None, verbose=False):
|
||||
def __init__(self, headerdir, verbose=False):
|
||||
if headerdir is None or len(headerdir) == 0:
|
||||
raise AssertionError("headerdir is not specified")
|
||||
|
||||
self.__headerdir = headerdir
|
||||
self.__debugdir = debugdir
|
||||
self.__verbose = verbose
|
||||
self.__debug_enabled = not (self.__debugdir is
|
||||
None) and len(self.__debugdir) > 0
|
||||
|
||||
self.platforms = ["windows", "mac", "linux"]
|
||||
|
||||
cef_dir = os.path.abspath(os.path.join(self.__headerdir, os.pardir))
|
||||
|
||||
# Read the variables list from the autogenerated cef_paths.gypi file.
|
||||
cef_paths = eval_file(os.path.join(cef_dir, 'cef_paths.gypi'))
|
||||
cef_paths = cef_paths['variables']
|
||||
|
||||
# Read the variables list from the manually edited cef_paths2.gypi file.
|
||||
cef_paths2 = eval_file(os.path.join(cef_dir, 'cef_paths2.gypi'))
|
||||
cef_paths2 = cef_paths2['variables']
|
||||
|
||||
# Excluded files (paths relative to the include/ directory).
|
||||
excluded_files = []
|
||||
|
||||
# List of platform-specific C API include/ files.
|
||||
self.platform_files = {
|
||||
# List of includes_win_capi from cef_paths2.gypi.
|
||||
"windows": [
|
||||
"internal/cef_app_win.h",
|
||||
"internal/cef_types_win.h",
|
||||
],
|
||||
# List of includes_mac_capi from cef_paths2.gypi.
|
||||
"mac": [
|
||||
"internal/cef_types_mac.h",
|
||||
],
|
||||
# List of includes_linux_capi from cef_paths2.gypi.
|
||||
"linux": [
|
||||
"internal/cef_types_linux.h",
|
||||
]
|
||||
"windows":
|
||||
self.__get_filenames(cef_dir, cef_paths2['includes_win_capi'],
|
||||
excluded_files),
|
||||
"mac":
|
||||
self.__get_filenames(cef_dir, cef_paths2['includes_mac_capi'],
|
||||
excluded_files),
|
||||
"linux":
|
||||
self.__get_filenames(cef_dir, cef_paths2['includes_linux_capi'],
|
||||
excluded_files)
|
||||
}
|
||||
|
||||
self.included_files = []
|
||||
# List of all C API include/ files.
|
||||
paths = cef_paths2['includes_capi'] + cef_paths2['includes_common_capi'] + \
|
||||
cef_paths2['includes_linux_capi'] + cef_paths2['includes_mac_capi'] + \
|
||||
cef_paths2['includes_win_capi'] + cef_paths['autogen_capi_includes']
|
||||
self.filenames = self.__get_filenames(cef_dir, paths, excluded_files)
|
||||
|
||||
# List of include/ and include/internal/ files from cef_paths2.gypi.
|
||||
self.excluded_files = [
|
||||
# includes_common
|
||||
"cef_api_hash.h",
|
||||
"cef_base.h",
|
||||
"cef_version.h",
|
||||
"internal/cef_export.h",
|
||||
"internal/cef_ptr.h",
|
||||
"internal/cef_string_wrappers.h",
|
||||
"internal/cef_time_wrappers.h",
|
||||
"internal/cef_types_wrappers.h",
|
||||
# includes_win
|
||||
"cef_sandbox_win.h",
|
||||
"internal/cef_win.h",
|
||||
# includes_mac
|
||||
"cef_application_mac.h",
|
||||
"cef_sandbox_mac.h",
|
||||
"internal/cef_mac.h",
|
||||
# includes_linux
|
||||
"internal/cef_linux.h",
|
||||
]
|
||||
self.filecontents = {}
|
||||
self.filecontentobjs = {}
|
||||
|
||||
def calculate(self):
|
||||
filenames = [
|
||||
filename for filename in self.__get_filenames()
|
||||
if not filename in self.excluded_files
|
||||
]
|
||||
|
||||
objects = []
|
||||
for filename in filenames:
|
||||
# Cache values that will not change between calls to calculate().
|
||||
for filename in self.filenames:
|
||||
if self.__verbose:
|
||||
print("Processing " + filename + "...")
|
||||
|
||||
assert not filename in self.filecontents, filename
|
||||
assert not filename in self.filecontentobjs, filename
|
||||
|
||||
content = read_file(os.path.join(self.__headerdir, filename), True)
|
||||
platforms = list([
|
||||
p for p in self.platforms if self.__is_platform_filename(filename, p)
|
||||
])
|
||||
content_objects = None
|
||||
|
||||
# Parse cef_string.h happens in special case: grab only defined CEF_STRING_TYPE_xxx declaration
|
||||
content_objects = None
|
||||
if filename == "internal/cef_string.h":
|
||||
content_objects = self.__parse_string_type(content)
|
||||
elif content.find('#if CEF_API') >= 0:
|
||||
# Needs to be passed to clang with version-specific defines.
|
||||
self.filecontents[filename] = content
|
||||
else:
|
||||
content_objects = self.__parse_objects(content)
|
||||
|
||||
for o in content_objects:
|
||||
o["text"] = self.__prepare_text(o["text"])
|
||||
o["platforms"] = platforms
|
||||
o["filename"] = filename
|
||||
objects.append(o)
|
||||
if not content_objects is None:
|
||||
self.__prepare_objects(filename, content_objects)
|
||||
self.filecontentobjs[filename] = content_objects
|
||||
|
||||
def calculate(self, api_version, debug_dir=None, added_defines=None):
|
||||
debug_enabled = not (debug_dir is None) and len(debug_dir) > 0
|
||||
|
||||
objects = []
|
||||
for filename in self.filenames:
|
||||
if self.__verbose:
|
||||
print("Processing " + filename + "...")
|
||||
|
||||
content = self.filecontents.get(filename, None)
|
||||
if not content is None:
|
||||
assert content.find('#if CEF_API') >= 0, filename
|
||||
content = _run_clang_eval(filename, content, api_version, added_defines,
|
||||
self.__verbose)
|
||||
if content is None:
|
||||
sys.stderr.write(
|
||||
'ERROR: Failed to compute API hash for %s\n' % filename)
|
||||
return False
|
||||
if debug_enabled:
|
||||
self.__write_debug_file(
|
||||
debug_dir, 'clang-' + filename.replace('/', '-'), content)
|
||||
content_objects = self.__parse_objects(content)
|
||||
self.__prepare_objects(filename, content_objects)
|
||||
else:
|
||||
content_objects = self.filecontentobjs.get(filename, None)
|
||||
|
||||
assert not content_objects is None, filename
|
||||
objects.extend(content_objects)
|
||||
|
||||
# objects will be sorted including filename, to make stable universal hashes
|
||||
objects = sorted(objects, key=lambda o: o["name"] + "@" + o["filename"])
|
||||
|
||||
if self.__debug_enabled:
|
||||
if debug_enabled:
|
||||
namelen = max([len(o["name"]) for o in objects])
|
||||
filenamelen = max([len(o["filename"]) for o in objects])
|
||||
dumpsig = []
|
||||
@@ -116,14 +195,14 @@ class cef_api_hash:
|
||||
dumpsig.append(
|
||||
format(o["name"], str(namelen) + "s") + "|" + format(
|
||||
o["filename"], "" + str(filenamelen) + "s") + "|" + o["text"])
|
||||
self.__write_debug_file("objects.txt", dumpsig)
|
||||
self.__write_debug_file(debug_dir, "objects.txt", dumpsig)
|
||||
|
||||
revisions = {}
|
||||
|
||||
for platform in itertools.chain(["universal"], self.platforms):
|
||||
sig = self.__get_final_sig(objects, platform)
|
||||
if self.__debug_enabled:
|
||||
self.__write_debug_file(platform + ".sig", sig)
|
||||
if debug_enabled:
|
||||
self.__write_debug_file(debug_dir, platform + ".sig", sig)
|
||||
revstr = hashlib.sha1(sig.encode('utf-8')).hexdigest()
|
||||
revisions[platform] = revstr
|
||||
|
||||
@@ -152,7 +231,8 @@ class cef_api_hash:
|
||||
|
||||
# enums
|
||||
for m in re.finditer(
|
||||
r"\ntypedef\s+?enum\s+?\{.*?\}\s+?(\w+)\s*?;", content, flags=re.DOTALL):
|
||||
r"\ntypedef\s+?enum\s+?\{.*?\}\s+?(\w+)\s*?;", content,
|
||||
flags=re.DOTALL):
|
||||
object = {"name": m.group(1), "text": m.group(0).strip()}
|
||||
objects.append(object)
|
||||
|
||||
@@ -163,11 +243,20 @@ class cef_api_hash:
|
||||
|
||||
return objects
|
||||
|
||||
def __prepare_objects(self, filename, objects):
|
||||
platforms = list(
|
||||
[p for p in self.platforms if self.__is_platform_filename(filename, p)])
|
||||
for o in objects:
|
||||
o["text"] = self.__prepare_text(o["text"])
|
||||
o["platforms"] = platforms
|
||||
o["filename"] = filename
|
||||
|
||||
def __parse_string_type(self, content):
|
||||
""" Grab defined CEF_STRING_TYPE_xxx """
|
||||
objects = []
|
||||
for m in re.finditer(
|
||||
r"\n\s*?#\s*?define\s+?(CEF_STRING_TYPE_\w+)\s+?.*?\n", content,
|
||||
r"\n\s*?#\s*?define\s+?(CEF_STRING_TYPE_\w+)\s+?.*?\n",
|
||||
content,
|
||||
flags=0):
|
||||
object = {
|
||||
"name": m.group(1),
|
||||
@@ -191,35 +280,20 @@ class cef_api_hash:
|
||||
|
||||
return "\n".join(sig)
|
||||
|
||||
def __get_filenames(self):
|
||||
def __get_filenames(self, cef_dir, paths, excluded_files):
|
||||
""" Returns file names to be processed, relative to headerdir """
|
||||
headers = [
|
||||
os.path.join(self.__headerdir, filename)
|
||||
for filename in self.included_files
|
||||
filenames = [
|
||||
os.path.relpath(os.path.join(cef_dir, filename),
|
||||
self.__headerdir).replace('\\', '/').lower()
|
||||
for filename in paths
|
||||
]
|
||||
|
||||
capi_dir = os.path.join(self.__headerdir, "capi")
|
||||
headers = itertools.chain(headers, get_files(os.path.join(capi_dir, "*.h")))
|
||||
if len(excluded_files) == 0:
|
||||
return filenames
|
||||
|
||||
# Also include capi sub-directories.
|
||||
for root, dirs, files in os.walk(capi_dir):
|
||||
for name in dirs:
|
||||
headers = itertools.chain(headers,
|
||||
get_files(os.path.join(root, name, "*.h")))
|
||||
|
||||
headers = itertools.chain(
|
||||
headers, get_files(os.path.join(self.__headerdir, "internal", "*.h")))
|
||||
|
||||
for v in self.platform_files.values():
|
||||
headers = itertools.chain(headers,
|
||||
[os.path.join(self.__headerdir, f) for f in v])
|
||||
|
||||
normalized = [
|
||||
os.path.relpath(filename, self.__headerdir) for filename in headers
|
||||
return [
|
||||
filename for filename in filenames if not filename in excluded_files
|
||||
]
|
||||
normalized = [f.replace('\\', '/').lower() for f in normalized]
|
||||
|
||||
return list(set(normalized))
|
||||
|
||||
def __is_platform_filename(self, filename, platform):
|
||||
if platform == "universal":
|
||||
@@ -235,9 +309,9 @@ class cef_api_hash:
|
||||
listed = True
|
||||
return not listed
|
||||
|
||||
def __write_debug_file(self, filename, content):
|
||||
make_dir(self.__debugdir)
|
||||
outfile = os.path.join(self.__debugdir, filename)
|
||||
def __write_debug_file(self, debug_dir, filename, content):
|
||||
make_dir(debug_dir)
|
||||
outfile = os.path.join(debug_dir, filename)
|
||||
dir = os.path.dirname(outfile)
|
||||
make_dir(dir)
|
||||
if not isinstance(content, string_type):
|
||||
@@ -282,14 +356,16 @@ if __name__ == "__main__":
|
||||
c_start_time = time.time()
|
||||
|
||||
calc = cef_api_hash(options.cppheaderdir, options.debugdir, options.verbose)
|
||||
revisions = calc.calculate()
|
||||
revisions = calc.calculate(api_version=EXP_VERSION)
|
||||
|
||||
c_completed_in = time.time() - c_start_time
|
||||
|
||||
print("{")
|
||||
for k in sorted(revisions.keys()):
|
||||
print(format("\"" + k + "\"", ">12s") + ": \"" + revisions[k] + "\"")
|
||||
print("}")
|
||||
if bool(revisions):
|
||||
print("{")
|
||||
for k in sorted(revisions.keys()):
|
||||
print(format("\"" + k + "\"", ">12s") + ": \"" + revisions[k] + "\"")
|
||||
print("}")
|
||||
|
||||
# print
|
||||
# print 'Completed in: ' + str(c_completed_in)
|
||||
# print
|
||||
|
@@ -3,6 +3,7 @@
|
||||
# can be found in the LICENSE file.
|
||||
|
||||
from __future__ import absolute_import
|
||||
import bisect
|
||||
from date_util import *
|
||||
from file_util import *
|
||||
import os
|
||||
@@ -12,11 +13,26 @@ import string
|
||||
import sys
|
||||
import textwrap
|
||||
import time
|
||||
from version_util import version_as_numeric, version_as_variable
|
||||
|
||||
_NOTIFY_CONTEXT = None
|
||||
_NOTIFY_CONTEXT_LAST = None
|
||||
|
||||
|
||||
def set_notify_context(context):
|
||||
global _NOTIFY_CONTEXT
|
||||
_NOTIFY_CONTEXT = context
|
||||
|
||||
|
||||
def notify(msg):
|
||||
""" Display a message. """
|
||||
sys.stdout.write(' NOTE: ' + msg + '\n')
|
||||
global _NOTIFY_CONTEXT_LAST
|
||||
|
||||
if not _NOTIFY_CONTEXT is None and _NOTIFY_CONTEXT != _NOTIFY_CONTEXT_LAST:
|
||||
print('In %s:' % _NOTIFY_CONTEXT)
|
||||
_NOTIFY_CONTEXT_LAST = _NOTIFY_CONTEXT
|
||||
|
||||
print(' NOTE: ' + msg)
|
||||
|
||||
|
||||
def wrap_text(text, indent='', maxchars=80, listitem=False):
|
||||
@@ -44,25 +60,28 @@ def is_base_class(clsname):
|
||||
return clsname == 'CefBaseRefCounted' or clsname == 'CefBaseScoped'
|
||||
|
||||
|
||||
def get_capi_file_name(cppname):
|
||||
def get_capi_file_name(cppname, versions=False):
|
||||
""" Convert a C++ header file name to a C API header file name. """
|
||||
return cppname[:-2] + '_capi.h'
|
||||
return cppname[:-2] + ('_capi_versions.h' if versions else '_capi.h')
|
||||
|
||||
|
||||
def get_capi_name(cppname, isclassname, prefix=None):
|
||||
def get_capi_name(cppname, isclassname, prefix=None, version=None):
|
||||
""" Convert a C++ CamelCaps name to a C API underscore name. """
|
||||
result = ''
|
||||
lastchr = ''
|
||||
for chr in cppname:
|
||||
# add an underscore if the current character is an upper case letter
|
||||
# and the last character was a lower case letter
|
||||
if len(result) > 0 and not chr.isdigit() \
|
||||
# and the last character was a lower case letter or number.
|
||||
if len(result) > 0 and chr.isalpha() \
|
||||
and chr.upper() == chr \
|
||||
and not lastchr.upper() == lastchr:
|
||||
and lastchr.isalnum() and lastchr.lower() == lastchr:
|
||||
result += '_'
|
||||
result += chr.lower()
|
||||
lastchr = chr
|
||||
|
||||
if isclassname and not version is None:
|
||||
result += '_%d' % version
|
||||
|
||||
if isclassname:
|
||||
result += '_t'
|
||||
|
||||
@@ -259,7 +278,10 @@ def format_translation_changes(old, new):
|
||||
return result
|
||||
|
||||
|
||||
def format_translation_includes(header, body):
|
||||
def format_translation_includes(header,
|
||||
body,
|
||||
with_versions=False,
|
||||
other_includes=None):
|
||||
""" Return the necessary list of includes based on the contents of the
|
||||
body.
|
||||
"""
|
||||
@@ -269,47 +291,187 @@ def format_translation_includes(header, body):
|
||||
if body.find('std::min') > 0 or body.find('std::max') > 0:
|
||||
result += '#include <algorithm>\n'
|
||||
|
||||
if body.find('cef_api_hash(') > 0:
|
||||
result += '#include "include/cef_api_hash.h"\n'
|
||||
paths = set()
|
||||
|
||||
if body.find('cef_api_hash(') > 0 or body.find('cef_api_version(') > 0:
|
||||
paths.add('include/cef_api_hash.h')
|
||||
|
||||
if body.find('template_util::has_valid_size(') > 0:
|
||||
result += '#include "libcef_dll/template_util.h"\n'
|
||||
paths.add('libcef_dll/template_util.h')
|
||||
|
||||
# identify what CppToC classes are being used
|
||||
p = re.compile(r'([A-Za-z0-9_]{1,})CppToC')
|
||||
list = sorted(set(p.findall(body)))
|
||||
for item in list:
|
||||
directory = ''
|
||||
if not is_base_class(item):
|
||||
cls = header.get_class(item)
|
||||
dir = cls.get_file_directory()
|
||||
if not dir is None:
|
||||
directory = dir + '/'
|
||||
result += '#include "libcef_dll/cpptoc/'+directory+ \
|
||||
get_capi_name(item[3:], False)+'_cpptoc.h"\n'
|
||||
|
||||
# identify what CToCpp classes are being used
|
||||
p = re.compile(r'([A-Za-z0-9_]{1,})CToCpp')
|
||||
list = sorted(set(p.findall(body)))
|
||||
for item in list:
|
||||
directory = ''
|
||||
if not is_base_class(item):
|
||||
cls = header.get_class(item)
|
||||
dir = cls.get_file_directory()
|
||||
if not dir is None:
|
||||
directory = dir + '/'
|
||||
result += '#include "libcef_dll/ctocpp/'+directory+ \
|
||||
get_capi_name(item[3:], False)+'_ctocpp.h"\n'
|
||||
search = ((True, True, r'([A-Za-z0-9_]{1,})_[0-9]{1,}_CppToC'),
|
||||
(True, False, r'([A-Za-z0-9_]{1,})CppToC'),
|
||||
(False, True, r'([A-Za-z0-9_]{1,})_[0-9]{1,}_CToCpp'),
|
||||
(False, False, r'([A-Za-z0-9_]{1,})CToCpp'))
|
||||
for cpptoc, versioned, regex in search:
|
||||
# identify what classes are being used
|
||||
p = re.compile(regex)
|
||||
items = set(p.findall(body))
|
||||
for item in items:
|
||||
if item == 'Cef':
|
||||
continue
|
||||
if not versioned and item[-1] == '_':
|
||||
# skip versioned names that are picked up by the unversioned regex
|
||||
continue
|
||||
directory = ''
|
||||
if not is_base_class(item):
|
||||
cls = header.get_class(item)
|
||||
if cls is None:
|
||||
raise Exception('Class does not exist: ' + item)
|
||||
dir = cls.get_file_directory()
|
||||
if not dir is None:
|
||||
directory = dir + '/'
|
||||
type = 'cpptoc' if cpptoc else 'ctocpp'
|
||||
paths.add('libcef_dll/' + type + '/'+directory+ \
|
||||
get_capi_name(item[3:], False)+'_' + type + '.h')
|
||||
|
||||
if body.find('shutdown_checker') > 0:
|
||||
result += '#include "libcef_dll/shutdown_checker.h"\n'
|
||||
paths.add('libcef_dll/shutdown_checker.h')
|
||||
|
||||
if body.find('transfer_') > 0:
|
||||
result += '#include "libcef_dll/transfer_util.h"\n'
|
||||
paths.add('libcef_dll/transfer_util.h')
|
||||
|
||||
if not other_includes is None:
|
||||
paths.update(other_includes)
|
||||
|
||||
if len(paths) > 0:
|
||||
if len(result) > 0:
|
||||
result += '\n'
|
||||
|
||||
paths = sorted(list(paths))
|
||||
result += '\n'.join(['#include "%s"' % p for p in paths]) + '\n'
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def format_notreached(library_side, msg, default_retval='', indent=' '):
|
||||
if library_side:
|
||||
return 'NOTREACHED() << __func__ << ' + msg + ';'
|
||||
return 'CHECK(false) << __func__ << ' + msg + ';\n' + \
|
||||
indent + 'return%s;' % ((' ' + default_retval) if len(default_retval) > 0 else '')
|
||||
|
||||
|
||||
def _has_version_added(attribs):
|
||||
return 'added' in attribs
|
||||
|
||||
|
||||
def _has_version_removed(attribs):
|
||||
return 'removed' in attribs
|
||||
|
||||
|
||||
def _has_version(attribs):
|
||||
return _has_version_added(attribs) or _has_version_removed(attribs)
|
||||
|
||||
|
||||
def get_version_check(attribs):
|
||||
assert _has_version(attribs)
|
||||
|
||||
added = attribs.get('added', None)
|
||||
if not added is None:
|
||||
added = version_as_variable(added)
|
||||
removed = attribs.get('removed', None)
|
||||
if not removed is None:
|
||||
removed = version_as_variable(removed)
|
||||
|
||||
if not added is None and not removed is None:
|
||||
return 'CEF_API_RANGE(%s, %s)' % (added, removed)
|
||||
elif not added is None:
|
||||
return 'CEF_API_ADDED(%s)' % added
|
||||
return 'CEF_API_REMOVED(%s)' % removed
|
||||
|
||||
|
||||
def _get_version_attrib(attribs, key):
|
||||
value = attribs.get(key, None)
|
||||
if not value is None:
|
||||
return version_as_numeric(value)
|
||||
|
||||
# Unversioned is always the first value.
|
||||
return 0
|
||||
|
||||
|
||||
def _get_version_added(attribs):
|
||||
""" Returns a numeric 'added' value used for sorting purposes. """
|
||||
return _get_version_attrib(attribs, 'added')
|
||||
|
||||
|
||||
def _get_version_removed(attribs):
|
||||
""" Returns a numeric 'removed' value used for sorting purposes. """
|
||||
return _get_version_attrib(attribs, 'removed')
|
||||
|
||||
|
||||
def get_version_surround(obj, long=False):
|
||||
""" Returns (pre,post) strings for a version check. """
|
||||
version_check = obj.get_version_check() if obj.has_version() else None
|
||||
|
||||
# Don't duplicate the surrounding class version check for a virtual method.
|
||||
if not version_check is None and \
|
||||
isinstance(obj, obj_function) and isinstance(obj.parent, obj_class) and \
|
||||
obj.parent.has_version() and obj.parent.get_version_check() == version_check:
|
||||
version_check = None
|
||||
|
||||
if not version_check is None:
|
||||
return ('#if %s\n' % version_check, ('#endif // %s\n' % version_check)
|
||||
if long else '#endif\n')
|
||||
return ('', '')
|
||||
|
||||
|
||||
def get_clsname(cls, version):
|
||||
name = cls.get_name()
|
||||
|
||||
if not version is None:
|
||||
# Select the appropriate version for this class.
|
||||
closest_version = cls.get_closest_version(version)
|
||||
if closest_version is None:
|
||||
raise Exception('Cannot find version <= %d for %s' % (version, name))
|
||||
return '%s_%d_' % (name, closest_version)
|
||||
|
||||
return name
|
||||
|
||||
|
||||
def _version_order_funcs(funcs, max_version=None):
|
||||
""" Applies version-based ordering to a list of funcs. """
|
||||
versions = {0: []}
|
||||
|
||||
for func in funcs:
|
||||
if func.has_version():
|
||||
added = func.get_version_added()
|
||||
if not added in versions:
|
||||
versions[added] = [func]
|
||||
else:
|
||||
versions[added].append(func)
|
||||
else:
|
||||
# Unversioned funcs.
|
||||
versions[0].append(func)
|
||||
|
||||
result = []
|
||||
for version in sorted(versions.keys()):
|
||||
if not max_version is None and version > max_version:
|
||||
break
|
||||
result.extend(versions[version])
|
||||
return result
|
||||
|
||||
|
||||
def _get_all_versions(funcs):
|
||||
# Using a set to ensure uniqueness.
|
||||
versions = set({0})
|
||||
|
||||
for func in funcs:
|
||||
if func.has_version():
|
||||
versions.add(func.get_version_added())
|
||||
versions.add(func.get_version_removed())
|
||||
|
||||
return versions
|
||||
|
||||
|
||||
def _find_closest_not_greater(lst, target):
|
||||
assert isinstance(lst, list), lst
|
||||
assert isinstance(target, int), target
|
||||
idx = bisect.bisect_right(lst, target) - 1
|
||||
if idx < 0:
|
||||
return None
|
||||
return lst[idx]
|
||||
|
||||
|
||||
def str_to_dict(str):
|
||||
""" Convert a string to a dictionary. If the same key has multiple values
|
||||
the values will be stored in a list. """
|
||||
@@ -357,6 +519,13 @@ def dict_to_str(dict):
|
||||
return ','.join(str)
|
||||
|
||||
|
||||
# Attribute keys allowed in CEF metadata comments.
|
||||
COMMON_ATTRIB_KEYS = ('added', 'removed')
|
||||
CLASS_ATTRIB_KEYS = COMMON_ATTRIB_KEYS + ('no_debugct_check', 'source')
|
||||
FUNCTION_ATTRIB_KEYS = COMMON_ATTRIB_KEYS + ('api_hash_check', 'capi_name',
|
||||
'count_func', 'default_retval',
|
||||
'index_param', 'optional_param')
|
||||
|
||||
# regex for matching comment-formatted attributes
|
||||
_cre_attrib = r'/\*--cef\(([A-Za-z0-9_ ,=:\n]{0,})\)--\*/'
|
||||
# regex for matching class and function names
|
||||
@@ -747,13 +916,18 @@ class obj_header:
|
||||
res.append(cls)
|
||||
return res
|
||||
|
||||
def get_class(self, classname, defined_structs=None):
|
||||
def get_class(self, classname):
|
||||
""" Return the specified class or None if not found. """
|
||||
for cls in self.classes:
|
||||
if cls.get_name() == classname:
|
||||
return cls
|
||||
elif not defined_structs is None:
|
||||
defined_structs.append(cls.get_capi_name())
|
||||
return None
|
||||
|
||||
def get_capi_class(self, classname):
|
||||
""" Return the specified class or None if not found. """
|
||||
for cls in self.classes:
|
||||
if cls.get_capi_name() == classname:
|
||||
return cls
|
||||
return None
|
||||
|
||||
def get_class_names(self):
|
||||
@@ -856,6 +1030,8 @@ class obj_class:
|
||||
self.includes = includes
|
||||
self.forward_declares = forward_declares
|
||||
|
||||
self._validate_attribs()
|
||||
|
||||
# extract typedefs
|
||||
p = re.compile(
|
||||
r'\n' + _cre_space + r'typedef' + _cre_space + _cre_typedef + r';',
|
||||
@@ -895,13 +1071,19 @@ class obj_class:
|
||||
|
||||
# build the virtual function objects
|
||||
self.virtualfuncs = []
|
||||
self.has_versioned_funcs = False
|
||||
for attrib, retval, argval, vfmod in list:
|
||||
comment = get_comment(body, retval + '(' + argval + ')')
|
||||
validate_comment(filename, retval, comment)
|
||||
if not self.has_versioned_funcs and _has_version(attrib):
|
||||
self.has_versioned_funcs = True
|
||||
self.virtualfuncs.append(
|
||||
obj_function_virtual(self, attrib, retval, argval, comment,
|
||||
vfmod.strip()))
|
||||
|
||||
self.virtualfuncs_ordered = None
|
||||
self.allversions = None
|
||||
|
||||
def __repr__(self):
|
||||
result = '/* ' + dict_to_str(
|
||||
self.attribs) + ' */ class ' + self.name + "\n{"
|
||||
@@ -930,15 +1112,21 @@ class obj_class:
|
||||
result += "\n};\n"
|
||||
return result
|
||||
|
||||
def _validate_attribs(self):
|
||||
for key in self.attribs.keys():
|
||||
if not key in CLASS_ATTRIB_KEYS:
|
||||
raise Exception('Invalid attribute key \"%s\" for class %s' %
|
||||
(key, self.get_name()))
|
||||
|
||||
def get_file_name(self):
|
||||
""" Return the C++ header file name. Includes the directory component,
|
||||
if any. """
|
||||
return self.filename
|
||||
|
||||
def get_capi_file_name(self):
|
||||
def get_capi_file_name(self, versions=False):
|
||||
""" Return the CAPI header file name. Includes the directory component,
|
||||
if any. """
|
||||
return get_capi_file_name(self.filename)
|
||||
return get_capi_file_name(self.filename, versions)
|
||||
|
||||
def get_file_directory(self):
|
||||
""" Return the file directory component, if any. """
|
||||
@@ -947,21 +1135,44 @@ class obj_class:
|
||||
return self.filename[:pos]
|
||||
return None
|
||||
|
||||
def get_name(self):
|
||||
def get_name(self, version=None):
|
||||
""" Return the class name. """
|
||||
if not version is None:
|
||||
# Select the appropriate version for this class.
|
||||
closest_version = self.get_closest_version(version)
|
||||
if closest_version is None:
|
||||
raise Exception('Cannot find version <= %d for %s' % (version,
|
||||
self.name))
|
||||
return '%s_%d_' % (self.name, closest_version)
|
||||
return self.name
|
||||
|
||||
def get_capi_name(self):
|
||||
def get_capi_name(self, version=None, first_version=False):
|
||||
""" Return the CAPI structure name for this class. """
|
||||
return get_capi_name(self.name, True)
|
||||
# Select the appropriate version for this class.
|
||||
if first_version:
|
||||
version = self.get_first_version()
|
||||
elif not version is None:
|
||||
closest_version = self.get_closest_version(version)
|
||||
if closest_version is None:
|
||||
raise Exception('Cannot find version <= %d for %s' % (version,
|
||||
self.name))
|
||||
version = closest_version
|
||||
return get_capi_name(self.name, True, version=version)
|
||||
|
||||
def get_parent_name(self):
|
||||
""" Return the parent class name. """
|
||||
return self.parent_name
|
||||
|
||||
def get_parent_capi_name(self):
|
||||
def get_parent_capi_name(self, version=None):
|
||||
""" Return the CAPI structure name for the parent class. """
|
||||
return get_capi_name(self.parent_name, True)
|
||||
if not version is None:
|
||||
# Select the appropriate version for the parent class.
|
||||
if is_base_class(self.parent_name):
|
||||
version = None
|
||||
else:
|
||||
parent_cls = self.parent.get_class(self.parent_name)
|
||||
version = parent_cls.get_closest_version(version)
|
||||
return get_capi_name(self.parent_name, True, version=version)
|
||||
|
||||
def has_parent(self, parent_name):
|
||||
""" Returns true if this class has the specified class anywhere in its
|
||||
@@ -1043,8 +1254,17 @@ class obj_class:
|
||||
""" Return the array of static function objects. """
|
||||
return self.staticfuncs
|
||||
|
||||
def get_virtual_funcs(self):
|
||||
def get_virtual_funcs(self, version_order=False, version=None):
|
||||
""" Return the array of virtual function objects. """
|
||||
if version_order and self.has_versioned_funcs:
|
||||
if version is None:
|
||||
# Cache the ordering result for future use.
|
||||
if self.virtualfuncs_ordered is None:
|
||||
self.virtualfuncs_ordered = _version_order_funcs(self.virtualfuncs)
|
||||
return self.virtualfuncs_ordered
|
||||
|
||||
# Need to order each time to apply the max version.
|
||||
return _version_order_funcs(self.virtualfuncs, version)
|
||||
return self.virtualfuncs
|
||||
|
||||
def get_types(self, list):
|
||||
@@ -1078,6 +1298,75 @@ class obj_class:
|
||||
""" Returns true if the class is implemented by the client. """
|
||||
return self.attribs['source'] == 'client'
|
||||
|
||||
def has_version(self):
|
||||
""" Returns true if the class has an associated version. """
|
||||
return _has_version(self.attribs)
|
||||
|
||||
def has_version_added(self):
|
||||
""" Returns true if the class has an associated 'added' version. """
|
||||
return _has_version_added(self.attribs)
|
||||
|
||||
def get_version_added(self):
|
||||
""" Returns the associated 'added' version. """
|
||||
return _get_version_added(self.attribs)
|
||||
|
||||
def has_version_removed(self):
|
||||
""" Returns true if the class has an associated 'removed' version. """
|
||||
return _has_version_removed(self.attribs)
|
||||
|
||||
def get_version_removed(self):
|
||||
""" Returns the associated 'removed' version. """
|
||||
return _get_version_removed(self.attribs)
|
||||
|
||||
def removed_at_version(self, version):
|
||||
""" Returns true if this class is removed at the specified version. """
|
||||
return self.has_version_removed() and self.get_version_removed() <= version
|
||||
|
||||
def exists_at_version(self, version):
|
||||
""" Returns true if this class exists at the specified version. """
|
||||
if self.has_version_added() and self.get_version_added() > version:
|
||||
return False
|
||||
return not self.removed_at_version(version)
|
||||
|
||||
def get_version_check(self):
|
||||
""" Returns the #if check for the associated version. """
|
||||
return get_version_check(self.attribs)
|
||||
|
||||
def get_all_versions(self):
|
||||
""" Returns all distinct versions of this class. """
|
||||
if not self.allversions is None:
|
||||
return self.allversions
|
||||
|
||||
# Using a set to ensure uniqueness.
|
||||
versions = set()
|
||||
|
||||
# Versions from class inheritance.
|
||||
if not is_base_class(self.parent_name):
|
||||
versions.update(
|
||||
self.parent.get_class(self.parent_name).get_all_versions())
|
||||
|
||||
# Versions from virtual methods.
|
||||
versions.update(_get_all_versions(self.virtualfuncs))
|
||||
|
||||
versions = list(versions)
|
||||
|
||||
# Clamp to class versions, if specified.
|
||||
if self.has_version_added():
|
||||
versions = [x for x in versions if x >= self.get_version_added()]
|
||||
if self.has_version_removed():
|
||||
versions = [x for x in versions if x < self.get_version_removed()]
|
||||
|
||||
self.allversions = sorted(versions)
|
||||
return self.allversions
|
||||
|
||||
def get_first_version(self):
|
||||
""" Returns the first version. """
|
||||
return self.get_all_versions()[0]
|
||||
|
||||
def get_closest_version(self, version):
|
||||
""" Returns the closest version to |version| that is not greater, or None. """
|
||||
return _find_closest_not_greater(self.get_all_versions(), version)
|
||||
|
||||
|
||||
class obj_typedef:
|
||||
""" Class representing a typedef statement. """
|
||||
@@ -1099,9 +1388,9 @@ class obj_typedef:
|
||||
""" Return the C++ header file name. """
|
||||
return self.filename
|
||||
|
||||
def get_capi_file_name(self):
|
||||
def get_capi_file_name(self, versions=False):
|
||||
""" Return the CAPI header file name. """
|
||||
return get_capi_file_name(self.filename)
|
||||
return get_capi_file_name(self.filename, versions)
|
||||
|
||||
def get_alias(self):
|
||||
""" Return the alias. """
|
||||
@@ -1131,6 +1420,8 @@ class obj_function:
|
||||
self.name = self.retval.remove_name()
|
||||
self.comment = comment
|
||||
|
||||
self._validate_attribs()
|
||||
|
||||
# build the argument objects
|
||||
self.arguments = []
|
||||
arglist = argval.split(',')
|
||||
@@ -1163,13 +1454,19 @@ class obj_function:
|
||||
def __repr__(self):
|
||||
return '/* ' + dict_to_str(self.attribs) + ' */ ' + self.get_cpp_proto()
|
||||
|
||||
def _validate_attribs(self):
|
||||
for key in self.attribs.keys():
|
||||
if not key in FUNCTION_ATTRIB_KEYS:
|
||||
raise Exception('Invalid attribute key \"%s\" for %s' %
|
||||
(key, self.get_qualified_name()))
|
||||
|
||||
def get_file_name(self):
|
||||
""" Return the C++ header file name. """
|
||||
return self.filename
|
||||
|
||||
def get_capi_file_name(self):
|
||||
def get_capi_file_name(self, versions=False):
|
||||
""" Return the CAPI header file name. """
|
||||
return get_capi_file_name(self.filename)
|
||||
return get_capi_file_name(self.filename, versions)
|
||||
|
||||
def get_name(self):
|
||||
""" Return the function name. """
|
||||
@@ -1186,9 +1483,7 @@ class obj_function:
|
||||
|
||||
def get_capi_name(self, prefix=None):
|
||||
""" Return the CAPI function name. """
|
||||
if 'capi_name' in self.attribs:
|
||||
return self.attribs['capi_name']
|
||||
return get_capi_name(self.name, False, prefix)
|
||||
return get_capi_name(self.get_attrib('capi_name', self.name), False, prefix)
|
||||
|
||||
def get_comment(self):
|
||||
""" Return the function comment as an array of lines. """
|
||||
@@ -1202,7 +1497,7 @@ class obj_function:
|
||||
""" Return true if the specified attribute exists. """
|
||||
return name in self.attribs
|
||||
|
||||
def get_attrib(self, name):
|
||||
def get_attrib(self, name, default=None):
|
||||
""" Return the first or only value for specified attribute. """
|
||||
if name in self.attribs:
|
||||
if isinstance(self.attribs[name], list):
|
||||
@@ -1211,7 +1506,7 @@ class obj_function:
|
||||
else:
|
||||
# the value is a string
|
||||
return self.attribs[name]
|
||||
return None
|
||||
return default
|
||||
|
||||
def get_attrib_list(self, name):
|
||||
""" Return all values for specified attribute as a list. """
|
||||
@@ -1237,10 +1532,15 @@ class obj_function:
|
||||
for cls in self.arguments:
|
||||
cls.get_types(list)
|
||||
|
||||
def get_capi_parts(self, defined_structs=[], isimpl=False, prefix=None):
|
||||
def get_capi_parts(self,
|
||||
defined_structs=[],
|
||||
isimpl=False,
|
||||
prefix=None,
|
||||
version=None,
|
||||
version_finder=None):
|
||||
""" Return the parts of the C API function definition. """
|
||||
retval = ''
|
||||
dict = self.retval.get_type().get_capi(defined_structs)
|
||||
dict = self.retval.get_type().get_capi(defined_structs, version_finder)
|
||||
if dict['format'] == 'single':
|
||||
retval = dict['value']
|
||||
|
||||
@@ -1249,7 +1549,7 @@ class obj_function:
|
||||
|
||||
if isinstance(self, obj_function_virtual):
|
||||
# virtual functions get themselves as the first argument
|
||||
str = 'struct _' + self.parent.get_capi_name() + '* self'
|
||||
str = 'struct _' + self.parent.get_capi_name(version=version) + '* self'
|
||||
if isinstance(self, obj_function_virtual) and self.is_const():
|
||||
# const virtual functions get const self pointers
|
||||
str = 'const ' + str
|
||||
@@ -1260,7 +1560,7 @@ class obj_function:
|
||||
if len(self.arguments) > 0:
|
||||
for cls in self.arguments:
|
||||
type = cls.get_type()
|
||||
dict = type.get_capi(defined_structs)
|
||||
dict = type.get_capi(defined_structs, version_finder)
|
||||
if dict['format'] == 'single':
|
||||
args.append(dict['value'])
|
||||
elif dict['format'] == 'multi-arg':
|
||||
@@ -1276,9 +1576,15 @@ class obj_function:
|
||||
|
||||
return {'retval': retval, 'name': name, 'args': args}
|
||||
|
||||
def get_capi_proto(self, defined_structs=[], isimpl=False, prefix=None):
|
||||
def get_capi_proto(self,
|
||||
defined_structs=[],
|
||||
isimpl=False,
|
||||
prefix=None,
|
||||
version=None,
|
||||
version_finder=None):
|
||||
""" Return the prototype of the C API function. """
|
||||
parts = self.get_capi_parts(defined_structs, isimpl, prefix)
|
||||
parts = self.get_capi_parts(defined_structs, isimpl, prefix, version,
|
||||
version_finder)
|
||||
result = parts['retval']+' '+parts['name']+ \
|
||||
'('+', '.join(parts['args'])+')'
|
||||
return result
|
||||
@@ -1336,6 +1642,14 @@ class obj_function:
|
||||
|
||||
return other_is_library_side == this_is_library_side
|
||||
|
||||
def has_version(self):
|
||||
""" Returns true if the class has an associated version. """
|
||||
return _has_version(self.attribs)
|
||||
|
||||
def get_version_check(self):
|
||||
""" Returns the #if check for the associated version. """
|
||||
return get_version_check(self.attribs)
|
||||
|
||||
|
||||
class obj_function_static(obj_function):
|
||||
""" Class representing a static function. """
|
||||
@@ -1377,6 +1691,34 @@ class obj_function_virtual(obj_function):
|
||||
""" Returns true if the method declaration is const. """
|
||||
return self.isconst
|
||||
|
||||
def has_version_added(self):
|
||||
""" Returns true if a 'added' value was specified. """
|
||||
return _has_version_added(self.attribs)
|
||||
|
||||
def get_version_added(self):
|
||||
""" Returns the numeric 'added' value, or 0 if unspecified.
|
||||
Used for sorting purposes only. """
|
||||
return _get_version_added(self.attribs)
|
||||
|
||||
def has_version_removed(self):
|
||||
""" Returns true if a 'removed' value was specified. """
|
||||
return _has_version_removed(self.attribs)
|
||||
|
||||
def get_version_removed(self):
|
||||
""" Returns the numeric 'removed' value, or 0 if unspecified.
|
||||
Used for sorting purposes only. """
|
||||
return _get_version_removed(self.attribs)
|
||||
|
||||
def removed_at_version(self, version):
|
||||
""" Returns true if this function is removed at the specified version. """
|
||||
return self.has_version_removed() and self.get_version_removed() <= version
|
||||
|
||||
def exists_at_version(self, version):
|
||||
""" Returns true if this function exists at the specified version. """
|
||||
if self.has_version_added() and self.get_version_added() > version:
|
||||
return False
|
||||
return not self.removed_at_version(version)
|
||||
|
||||
|
||||
class obj_argument:
|
||||
""" Class representing a function argument. """
|
||||
@@ -1907,12 +2249,15 @@ class obj_analysis:
|
||||
""" Return the *Ptr type structure name. """
|
||||
return self.result_value[:-1]
|
||||
|
||||
def get_result_ptr_type(self, defined_structs=[]):
|
||||
def get_result_ptr_type(self, defined_structs=[], version_finder=None):
|
||||
""" Return the *Ptr type. """
|
||||
result = ''
|
||||
if not self.result_value[:-1] in defined_structs:
|
||||
name = self.result_value[:-1]
|
||||
if not version_finder is None:
|
||||
name = version_finder(name)
|
||||
if not name in defined_structs:
|
||||
result += 'struct _'
|
||||
result += self.result_value
|
||||
result += name + self.result_value[-1]
|
||||
if self.is_byref() or self.is_byaddr():
|
||||
result += '*'
|
||||
return result
|
||||
@@ -1951,16 +2296,22 @@ class obj_analysis:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_result_struct_type(self, defined_structs=[]):
|
||||
def get_result_struct_type(self, defined_structs=[], version_finder=None):
|
||||
""" Return the structure or enumeration type. """
|
||||
result = ''
|
||||
|
||||
name = self.result_value
|
||||
|
||||
is_enum = self.is_result_struct_enum()
|
||||
if not is_enum:
|
||||
if self.is_const():
|
||||
result += 'const '
|
||||
if not self.result_value in defined_structs:
|
||||
result += 'struct _'
|
||||
result += self.result_value
|
||||
if not version_finder is None:
|
||||
name = version_finder(name)
|
||||
|
||||
result += name
|
||||
if not is_enum:
|
||||
result += '*'
|
||||
return result
|
||||
@@ -2026,7 +2377,7 @@ class obj_analysis:
|
||||
""" Return the vector structure or basic type name. """
|
||||
return self.result_value[0]['result_value']
|
||||
|
||||
def get_result_vector_type(self, defined_structs=[]):
|
||||
def get_result_vector_type(self, defined_structs=[], version_finder=None):
|
||||
""" Return the vector type. """
|
||||
if not self.has_name():
|
||||
raise Exception('Cannot use vector as a return type')
|
||||
@@ -2048,9 +2399,15 @@ class obj_analysis:
|
||||
result['value'] = str
|
||||
elif type == 'refptr' or type == 'ownptr' or type == 'rawptr':
|
||||
str = ''
|
||||
if not value[:-1] in defined_structs:
|
||||
|
||||
# remove the * suffix
|
||||
name = value[:-1]
|
||||
if not version_finder is None:
|
||||
name = version_finder(name)
|
||||
|
||||
if not name in defined_structs:
|
||||
str += 'struct _'
|
||||
str += value
|
||||
str += name + value[-1]
|
||||
if self.is_const():
|
||||
str += ' const'
|
||||
str += '*'
|
||||
@@ -2087,16 +2444,16 @@ class obj_analysis:
|
||||
return {'value': 'cef_string_multimap_t', 'format': 'multi'}
|
||||
raise Exception('Only mappings of strings to strings are supported')
|
||||
|
||||
def get_capi(self, defined_structs=[]):
|
||||
def get_capi(self, defined_structs=[], version_finder=None):
|
||||
""" Format the value for the C API. """
|
||||
result = ''
|
||||
format = 'single'
|
||||
if self.is_result_simple():
|
||||
result += self.get_result_simple_type()
|
||||
elif self.is_result_ptr():
|
||||
result += self.get_result_ptr_type(defined_structs)
|
||||
result += self.get_result_ptr_type(defined_structs, version_finder)
|
||||
elif self.is_result_struct():
|
||||
result += self.get_result_struct_type(defined_structs)
|
||||
result += self.get_result_struct_type(defined_structs, version_finder)
|
||||
elif self.is_result_string():
|
||||
result += self.get_result_string_type()
|
||||
elif self.is_result_map():
|
||||
@@ -2106,7 +2463,7 @@ class obj_analysis:
|
||||
else:
|
||||
raise Exception('Unsupported map type')
|
||||
elif self.is_result_vector():
|
||||
resdict = self.get_result_vector_type(defined_structs)
|
||||
resdict = self.get_result_vector_type(defined_structs, version_finder)
|
||||
if resdict['format'] != 'single':
|
||||
format = resdict['format']
|
||||
result += resdict['value']
|
||||
|
@@ -7,6 +7,7 @@ from __future__ import print_function
|
||||
from file_util import *
|
||||
import git_util as git
|
||||
import os
|
||||
from version_util import read_version_last, version_parse, VERSIONS_JSON_FILE
|
||||
|
||||
|
||||
class VersionFormatter:
|
||||
@@ -46,15 +47,18 @@ class VersionFormatter:
|
||||
if not bool(self._chrome_version):
|
||||
file_path = os.path.join(self.src_path, 'chrome', 'VERSION')
|
||||
assert os.path.isfile(file_path), file_path
|
||||
read_version_file(file_path, self._chrome_version)
|
||||
assert read_version_file(file_path, self._chrome_version), file_path
|
||||
return self._chrome_version
|
||||
|
||||
def get_chrome_major_version(self):
|
||||
return self.get_chrome_version_components()['MAJOR']
|
||||
|
||||
def get_cef_version_components(self):
|
||||
""" Returns CEF version components. """
|
||||
if not bool(self._cef_version):
|
||||
file_path = os.path.join(self.cef_path, 'VERSION.in')
|
||||
assert os.path.isfile(file_path), file_path
|
||||
read_version_file(file_path, self._cef_version)
|
||||
assert read_version_file(file_path, self._cef_version), file_path
|
||||
return self._cef_version
|
||||
|
||||
def get_cef_commit_components(self):
|
||||
@@ -75,11 +79,11 @@ class VersionFormatter:
|
||||
# branch since branching from origin/master.
|
||||
hashes = git.get_branch_hashes(self.cef_path)
|
||||
for hash in hashes:
|
||||
# Determine if the API hash file was modified by the commit.
|
||||
# Determine if the API versions file was modified by the commit.
|
||||
found = False
|
||||
files = git.get_changed_files(self.cef_path, hash)
|
||||
for file in files:
|
||||
if file.find('cef_api_hash.h') >= 0:
|
||||
if file.find(VERSIONS_JSON_FILE) >= 0:
|
||||
found = True
|
||||
break
|
||||
|
||||
@@ -89,6 +93,14 @@ class VersionFormatter:
|
||||
else:
|
||||
bugfix += 1
|
||||
|
||||
last_version = read_version_last(
|
||||
os.path.join(self.cef_path, VERSIONS_JSON_FILE))
|
||||
if not last_version is None:
|
||||
major, revision = version_parse(last_version)
|
||||
if major == int(self.get_chrome_major_version()) and revision > minor:
|
||||
# Override the computed minor version with the last specified API version.
|
||||
minor = revision
|
||||
|
||||
self._branch_version = {'MINOR': minor, 'PATCH': bugfix}
|
||||
return self._branch_version
|
||||
|
||||
@@ -149,8 +161,8 @@ class VersionFormatter:
|
||||
# - "X" is the Chromium major version (e.g. 74).
|
||||
# - "Y" is an incremental number that starts at 0 when a release branch is
|
||||
# created and changes only when the CEF C/C++ API changes (similar to how
|
||||
# the CEF_API_HASH_UNIVERSAL value behaves in cef_version.h) (release branch
|
||||
# only).
|
||||
# the CEF_API_HASH_UNIVERSAL value behaves in cef_api_hash.h) (release
|
||||
# branch only).
|
||||
# - "Z" is an incremental number that starts at 0 when a release branch is
|
||||
# created and changes on each commit, with reset to 0 when "Y" changes
|
||||
# (release branch only).
|
||||
@@ -186,9 +198,15 @@ class VersionFormatter:
|
||||
# if we can get the name of the branch we are on (may be just "HEAD").
|
||||
cef_branch_name = git.get_branch_name(self.cef_path).split('/')[-1]
|
||||
|
||||
cef_minor = cef_patch = 0
|
||||
if cef_branch_name != 'HEAD' and cef_branch_name != 'master':
|
||||
cef_branch = self.get_cef_branch_version_components()
|
||||
cef_minor = cef_branch['MINOR']
|
||||
cef_patch = cef_branch['PATCH']
|
||||
|
||||
self._version_parts = {'MAJOR': int(chrome_major), 'MINOR': 0, 'PATCH': 0}
|
||||
self._version_string = '%s.0.0-%s.%s+%s+%s' % \
|
||||
(chrome_major, cef_branch_name, cef_commit['NUMBER'],
|
||||
self._version_string = '%s.%d.%d-%s.%s+%s+%s' % \
|
||||
(chrome_major, cef_minor, cef_patch, cef_branch_name, cef_commit['NUMBER'],
|
||||
cef_commit_hash, chrome_version_part)
|
||||
else:
|
||||
cef_branch = self.get_cef_branch_version_components()
|
||||
|
@@ -10,22 +10,66 @@ import sys
|
||||
|
||||
# Script directory.
|
||||
script_dir = os.path.dirname(__file__)
|
||||
root_dir = os.path.join(script_dir, os.pardir)
|
||||
cef_dir = os.path.join(script_dir, os.pardir)
|
||||
src_dir = os.path.abspath(os.path.join(cef_dir, os.pardir))
|
||||
llvm_bin_dir = os.path.join(src_dir,
|
||||
'third_party/llvm-build/Release+Asserts/bin')
|
||||
|
||||
if sys.platform == 'win32':
|
||||
# Force use of the clang-format version bundled with depot_tools.
|
||||
clang_format_exe = 'clang-format.bat'
|
||||
clang_exe = os.path.join(llvm_bin_dir, 'clang-cl.exe')
|
||||
else:
|
||||
clang_format_exe = 'clang-format'
|
||||
clang_exe = os.path.join(llvm_bin_dir, 'clang')
|
||||
|
||||
|
||||
def clang_format(file_name, file_contents):
|
||||
# -assume-filename is necessary to find the .clang-format file and determine
|
||||
# the language when specifying contents via stdin.
|
||||
result = exec_cmd("%s -assume-filename=%s" % (clang_format_exe, file_name), \
|
||||
root_dir, file_contents.encode('utf-8'))
|
||||
cef_dir, file_contents.encode('utf-8'))
|
||||
if result['err'] != '':
|
||||
print("clang-format error: %s" % result['err'])
|
||||
sys.stderr.write("clang-format error: %s\n" % result['err'])
|
||||
if result['out'] != '':
|
||||
output = result['out']
|
||||
if sys.platform == 'win32':
|
||||
# Convert to Unix line endings.
|
||||
output = output.replace("\r", "")
|
||||
return output
|
||||
return None
|
||||
|
||||
|
||||
def clang_format_inplace(file_name):
|
||||
result = exec_cmd("%s -i %s" % (clang_format_exe, file_name), cef_dir)
|
||||
if result['err'] != '':
|
||||
sys.stderr.write("clang-format error: %s\n" % result['err'])
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def clang_eval(file_name,
|
||||
file_contents,
|
||||
defines=[],
|
||||
includes=[],
|
||||
as_cpp=True,
|
||||
verbose=False):
|
||||
lang = 'c++' if as_cpp else 'c'
|
||||
if file_name.lower().endswith('.h'):
|
||||
lang += '-header'
|
||||
# The -P option removes unnecessary line markers and whitespace.
|
||||
format = '/EP' if sys.platform == 'win32' else '-E -P'
|
||||
cmd = "%s -x %s %s %s %s -" % (clang_exe, lang, format,
|
||||
' '.join(['-D' + v for v in defines]),
|
||||
' '.join(['-I' + v for v in includes]))
|
||||
if verbose:
|
||||
print('--- Running "%s" in "%s"' % (cmd, cef_dir))
|
||||
|
||||
result = exec_cmd(cmd, cef_dir, file_contents.encode('utf-8'))
|
||||
if result['err'] != '':
|
||||
err = result['err'].replace('<stdin>', file_name)
|
||||
sys.stderr.write("clang error: %s\n" % err)
|
||||
return None
|
||||
if result['out'] != '':
|
||||
output = result['out']
|
||||
if sys.platform == 'win32':
|
||||
|
@@ -3,35 +3,45 @@
|
||||
# can be found in the LICENSE file.
|
||||
|
||||
from __future__ import absolute_import
|
||||
import codecs
|
||||
import fnmatch
|
||||
from glob import iglob
|
||||
from io import open
|
||||
import json
|
||||
import os
|
||||
import fnmatch
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
def read_file(name, normalize=True):
|
||||
def read_file(path, normalize=True):
|
||||
""" Read a file. """
|
||||
try:
|
||||
with open(name, 'r', encoding='utf-8') as f:
|
||||
# read the data
|
||||
data = f.read()
|
||||
if normalize:
|
||||
# normalize line endings
|
||||
data = data.replace("\r\n", "\n")
|
||||
return data
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to read file ' + name + ': ' + strerror)
|
||||
raise
|
||||
if os.path.isfile(path):
|
||||
try:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
# read the data
|
||||
data = f.read()
|
||||
if normalize:
|
||||
# normalize line endings
|
||||
data = data.replace("\r\n", "\n")
|
||||
return data
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('ERROR: Failed to read file ' + path + ': ' + strerror)
|
||||
raise
|
||||
return None
|
||||
|
||||
|
||||
def write_file(name, data):
|
||||
def write_file(path, data, overwrite=True, quiet=True):
|
||||
""" Write a file. """
|
||||
if not overwrite and os.path.exists(path):
|
||||
return False
|
||||
|
||||
if not quiet:
|
||||
print('Writing file %s' % path)
|
||||
|
||||
try:
|
||||
with open(name, 'w', encoding='utf-8', newline='\n') as f:
|
||||
with open(path, 'w', encoding='utf-8', newline='\n') as f:
|
||||
# write the data
|
||||
if sys.version_info.major == 2:
|
||||
f.write(data.decode('utf-8'))
|
||||
@@ -39,57 +49,67 @@ def write_file(name, data):
|
||||
f.write(data)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to write file ' + name + ': ' + strerror)
|
||||
sys.stderr.write('ERROR: Failed to write file ' + path + ': ' + strerror)
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def path_exists(name):
|
||||
def path_exists(path):
|
||||
""" Returns true if the path currently exists. """
|
||||
return os.path.exists(name)
|
||||
return os.path.exists(path)
|
||||
|
||||
|
||||
def write_file_if_changed(name, data):
|
||||
def write_file_if_changed(path, data, quiet=True):
|
||||
""" Write a file if the contents have changed. Returns True if the file was written. """
|
||||
if path_exists(name):
|
||||
old_contents = read_file(name)
|
||||
if path_exists(path):
|
||||
old_contents = read_file(path)
|
||||
assert not old_contents is None, path
|
||||
else:
|
||||
old_contents = ''
|
||||
|
||||
if (data != old_contents):
|
||||
write_file(name, data)
|
||||
write_file(path, data, quiet=quiet)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def backup_file(name):
|
||||
def backup_file(path):
|
||||
""" Rename the file to a name that includes the current time stamp. """
|
||||
move_file(name, name + '.' + time.strftime('%Y-%m-%d-%H-%M-%S'))
|
||||
move_file(path, path + '.' + time.strftime('%Y-%m-%d-%H-%M-%S'))
|
||||
|
||||
|
||||
def copy_file(src, dst, quiet=True):
|
||||
""" Copy a file. """
|
||||
if not os.path.isfile(src):
|
||||
return False
|
||||
|
||||
try:
|
||||
shutil.copy2(src, dst)
|
||||
if not quiet:
|
||||
sys.stdout.write('Transferring ' + src + ' file.\n')
|
||||
shutil.copy2(src, dst)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to copy file from ' + src + ' to ' + dst + ': ' +
|
||||
strerror)
|
||||
sys.stderr.write('ERROR: Failed to copy file from ' + src + ' to ' + dst +
|
||||
': ' + strerror)
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def move_file(src, dst, quiet=True):
|
||||
""" Move a file. """
|
||||
if not os.path.isfile(src):
|
||||
return False
|
||||
|
||||
try:
|
||||
shutil.move(src, dst)
|
||||
if not quiet:
|
||||
sys.stdout.write('Moving ' + src + ' file.\n')
|
||||
print('Moving ' + src + ' file.')
|
||||
shutil.move(src, dst)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to move file from ' + src + ' to ' + dst + ': ' +
|
||||
strerror)
|
||||
sys.stderr.write('ERROR: Failed to move file from ' + src + ' to ' + dst +
|
||||
': ' + strerror)
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def copy_files(src_glob, dst_folder, quiet=True):
|
||||
@@ -102,56 +122,62 @@ def copy_files(src_glob, dst_folder, quiet=True):
|
||||
copy_file(fname, dst, quiet)
|
||||
|
||||
|
||||
def remove_file(name, quiet=True):
|
||||
def remove_file(path, quiet=True):
|
||||
""" Remove the specified file. """
|
||||
try:
|
||||
if path_exists(name):
|
||||
os.remove(name)
|
||||
if path_exists(path):
|
||||
if not quiet:
|
||||
sys.stdout.write('Removing ' + name + ' file.\n')
|
||||
print('Removing ' + path + ' file.')
|
||||
os.remove(path)
|
||||
return True
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to remove file ' + name + ': ' + strerror)
|
||||
sys.stderr.write('ERROR: Failed to remove file ' + path + ': ' + strerror)
|
||||
raise
|
||||
return False
|
||||
|
||||
|
||||
def copy_dir(src, dst, quiet=True):
|
||||
""" Copy a directory tree. """
|
||||
try:
|
||||
remove_dir(dst, quiet)
|
||||
shutil.copytree(src, dst)
|
||||
if not quiet:
|
||||
sys.stdout.write('Transferring ' + src + ' directory.\n')
|
||||
print('Transferring ' + src + ' directory.')
|
||||
shutil.copytree(src, dst)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to copy directory from ' + src + ' to ' + dst +
|
||||
': ' + strerror)
|
||||
sys.stderr.write('ERROR: Failed to copy directory from ' + src + ' to ' +
|
||||
dst + ': ' + strerror)
|
||||
raise
|
||||
|
||||
|
||||
def remove_dir(name, quiet=True):
|
||||
def remove_dir(path, quiet=True):
|
||||
""" Remove the specified directory. """
|
||||
try:
|
||||
if path_exists(name):
|
||||
shutil.rmtree(name)
|
||||
if path_exists(path):
|
||||
if not quiet:
|
||||
sys.stdout.write('Removing ' + name + ' directory.\n')
|
||||
print('Removing ' + path + ' directory.')
|
||||
shutil.rmtree(path)
|
||||
return True
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to remove directory ' + name + ': ' + strerror)
|
||||
sys.stderr.write('ERROR: Failed to remove directory ' + path + ': ' +
|
||||
strerror)
|
||||
raise
|
||||
return False
|
||||
|
||||
|
||||
def make_dir(name, quiet=True):
|
||||
def make_dir(path, quiet=True):
|
||||
""" Create the specified directory. """
|
||||
try:
|
||||
if not path_exists(name):
|
||||
if not path_exists(path):
|
||||
if not quiet:
|
||||
sys.stdout.write('Creating ' + name + ' directory.\n')
|
||||
os.makedirs(name)
|
||||
print('Creating ' + path + ' directory.')
|
||||
os.makedirs(path)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to create directory ' + name + ': ' + strerror)
|
||||
sys.stderr.write('ERROR: Failed to create directory ' + path + ': ' +
|
||||
strerror)
|
||||
raise
|
||||
|
||||
|
||||
@@ -180,13 +206,17 @@ def get_files_recursive(directory, pattern):
|
||||
yield filename
|
||||
|
||||
|
||||
def read_version_file(file, args):
|
||||
def read_version_file(path, args):
|
||||
""" Read and parse a version file (key=value pairs, one per line). """
|
||||
lines = read_file(file).split("\n")
|
||||
contents = read_file(path)
|
||||
if contents is None:
|
||||
return False
|
||||
lines = contents.split("\n")
|
||||
for line in lines:
|
||||
parts = line.split('=', 1)
|
||||
if len(parts) == 2:
|
||||
args[parts[0]] = parts[1]
|
||||
return True
|
||||
|
||||
|
||||
def eval_file(src):
|
||||
@@ -199,3 +229,48 @@ def normalize_path(path):
|
||||
if sys.platform == 'win32':
|
||||
return path.replace('\\', '/')
|
||||
return path
|
||||
|
||||
|
||||
def read_json_file(path):
|
||||
""" Read and parse a JSON file. Returns a list/dictionary or None. """
|
||||
if os.path.isfile(path):
|
||||
try:
|
||||
with codecs.open(path, 'r', encoding='utf-8') as fp:
|
||||
return json.load(fp)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('ERROR: Failed to read file ' + path + ': ' + strerror)
|
||||
raise
|
||||
return None
|
||||
|
||||
|
||||
def _bytes_encoder(z):
|
||||
if isinstance(z, bytes):
|
||||
return str(z, 'utf-8')
|
||||
else:
|
||||
type_name = z.__class__.__name__
|
||||
raise TypeError(f"Object of type {type_name} is not serializable")
|
||||
|
||||
|
||||
def write_json_file(path, data, overwrite=True, quiet=True):
|
||||
""" Serialize and write a JSON file. Returns True on success. """
|
||||
if not overwrite and os.path.exists(path):
|
||||
return False
|
||||
|
||||
if not quiet:
|
||||
print('Writing file %s' % path)
|
||||
|
||||
try:
|
||||
with open(path, 'w', encoding='utf-8') as fp:
|
||||
json.dump(
|
||||
data,
|
||||
fp,
|
||||
ensure_ascii=False,
|
||||
indent=2,
|
||||
sort_keys=True,
|
||||
default=_bytes_encoder)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('ERROR: Failed to write file ' + path + ': ' + strerror)
|
||||
raise
|
||||
return True
|
||||
|
@@ -28,8 +28,8 @@ else:
|
||||
print('Unknown operating system platform')
|
||||
sys.exit()
|
||||
|
||||
print("\nGenerating CEF version header file...")
|
||||
cmd = [sys.executable, 'tools/make_version_header.py', 'include/cef_version.h']
|
||||
print("\nGenerating CEF translated files...")
|
||||
cmd = [sys.executable, 'tools/version_manager.py', '-u', '--fast-check']
|
||||
RunAction(cef_dir, cmd)
|
||||
|
||||
print("\nPatching build configuration and source files for CEF...")
|
||||
|
@@ -26,85 +26,80 @@ def is_ancestor(path='.', commit1='HEAD', commit2='master'):
|
||||
return result['ret'] == 0
|
||||
|
||||
|
||||
def get_hash(path='.', branch='HEAD'):
|
||||
""" Returns the git hash for the specified branch/tag/hash. """
|
||||
cmd = "%s rev-parse %s" % (git_exe, branch)
|
||||
def exec_git_cmd(args, path='.'):
|
||||
""" Executes a git command with the specified |args|. """
|
||||
cmd = "%s %s" % (git_exe, args)
|
||||
result = exec_cmd(cmd, path)
|
||||
if result['out'] != '':
|
||||
return result['out'].strip()
|
||||
return 'Unknown'
|
||||
out = result['out'].strip()
|
||||
if sys.platform == 'win32':
|
||||
# Convert to Unix line endings.
|
||||
out = out.replace('\r\n', '\n')
|
||||
return out
|
||||
return None
|
||||
|
||||
|
||||
def get_hash(path='.', branch='HEAD'):
|
||||
""" Returns the git hash for the specified branch/tag/hash. """
|
||||
cmd = "rev-parse %s" % branch
|
||||
result = exec_git_cmd(cmd, path)
|
||||
return 'Unknown' if result is None else result
|
||||
|
||||
|
||||
def get_branch_name(path='.', branch='HEAD'):
|
||||
""" Returns the branch name for the specified branch/tag/hash. """
|
||||
# Returns the branch name if not in detached HEAD state, else an empty string
|
||||
# or "HEAD".
|
||||
cmd = "%s rev-parse --abbrev-ref %s" % (git_exe, branch)
|
||||
result = exec_cmd(cmd, path)
|
||||
if result['out'] != '':
|
||||
name = result['out'].strip()
|
||||
if len(name) > 0 and name != 'HEAD':
|
||||
return name
|
||||
cmd = "rev-parse --abbrev-ref %s" % branch
|
||||
result = exec_git_cmd(cmd, path)
|
||||
if result is None:
|
||||
return 'Unknown'
|
||||
if result != 'HEAD':
|
||||
return result
|
||||
|
||||
# Returns a value like "(HEAD, origin/3729, 3729)".
|
||||
# Ubuntu 14.04 uses Git version 1.9.1 which does not support %D (which
|
||||
# provides the same output but without the parentheses).
|
||||
cmd = "%s log -n 1 --pretty=%%d %s" % (git_exe, branch)
|
||||
result = exec_cmd(cmd, path)
|
||||
if result['out'] != '':
|
||||
return result['out'].strip()[1:-1].split(', ')[-1]
|
||||
return 'Unknown'
|
||||
# Returns a value like "(HEAD, origin/3729, 3729)".
|
||||
# Ubuntu 14.04 uses Git version 1.9.1 which does not support %D (which
|
||||
# provides the same output but without the parentheses).
|
||||
cmd = "log -n 1 --pretty=%%d %s" % branch
|
||||
result = exec_git_cmd(cmd, path)
|
||||
return 'Unknown' if result is None else result[1:-1].split(', ')[-1]
|
||||
|
||||
|
||||
def get_url(path='.'):
|
||||
""" Returns the origin url for the specified path. """
|
||||
cmd = "%s config --get remote.origin.url" % git_exe
|
||||
result = exec_cmd(cmd, path)
|
||||
if result['out'] != '':
|
||||
return result['out'].strip()
|
||||
return 'Unknown'
|
||||
cmd = "config --get remote.origin.url"
|
||||
result = exec_git_cmd(cmd, path)
|
||||
return 'Unknown' if result is None else result
|
||||
|
||||
|
||||
def get_commit_number(path='.', branch='HEAD'):
|
||||
""" Returns the number of commits in the specified branch/tag/hash. """
|
||||
cmd = "%s rev-list --count %s" % (git_exe, branch)
|
||||
result = exec_cmd(cmd, path)
|
||||
if result['out'] != '':
|
||||
return result['out'].strip()
|
||||
return '0'
|
||||
cmd = "rev-list --count %s" % (branch)
|
||||
result = exec_git_cmd(cmd, path)
|
||||
return '0' if result is None else result
|
||||
|
||||
|
||||
def get_changed_files(path, hash):
|
||||
""" Retrieves the list of changed files. """
|
||||
if hash == 'unstaged':
|
||||
cmd = "%s diff --name-only" % git_exe
|
||||
cmd = "diff --name-only"
|
||||
elif hash == 'staged':
|
||||
cmd = "%s diff --name-only --cached" % git_exe
|
||||
cmd = "diff --name-only --cached"
|
||||
else:
|
||||
cmd = "%s diff-tree --no-commit-id --name-only -r %s" % (git_exe, hash)
|
||||
result = exec_cmd(cmd, path)
|
||||
if result['out'] != '':
|
||||
files = result['out']
|
||||
if sys.platform == 'win32':
|
||||
# Convert to Unix line endings.
|
||||
files = files.replace('\r\n', '\n')
|
||||
return files.strip().split("\n")
|
||||
return []
|
||||
cmd = "diff-tree --no-commit-id --name-only -r %s" % hash
|
||||
result = exec_git_cmd(cmd, path)
|
||||
return [] if result is None else result.split("\n")
|
||||
|
||||
|
||||
def get_branch_hashes(path='.', branch='HEAD', ref='origin/master'):
|
||||
""" Returns an ordered list of hashes for commits that have been applied since
|
||||
branching from ref. """
|
||||
cmd = "%s cherry %s %s" % (git_exe, ref, branch)
|
||||
result = exec_cmd(cmd, path)
|
||||
if result['out'] != '':
|
||||
hashes = result['out']
|
||||
if sys.platform == 'win32':
|
||||
# Convert to Unix line endings.
|
||||
hashes = hashes.replace('\r\n', '\n')
|
||||
# Remove the "+ " or "- " prefix.
|
||||
return [line[2:] for line in hashes.strip().split('\n')]
|
||||
return []
|
||||
cmd = "cherry %s %s" % (ref, branch)
|
||||
result = exec_git_cmd(cmd, path)
|
||||
if result is None:
|
||||
return []
|
||||
# Remove the "+ " or "- " prefix.
|
||||
return [line[2:] for line in result.split('\n')]
|
||||
|
||||
|
||||
def write_indented_output(output):
|
||||
|
@@ -87,9 +87,12 @@ else:
|
||||
print('Unknown operating system platform')
|
||||
sys.exit()
|
||||
|
||||
_QUIET = False
|
||||
|
||||
|
||||
def msg(msg):
|
||||
print('NOTE: ' + msg)
|
||||
if not _QUIET:
|
||||
print('NOTE: ' + msg)
|
||||
|
||||
|
||||
def NameValueListToDict(name_value_list):
|
||||
@@ -591,12 +594,16 @@ def LinuxSysrootExists(cpu):
|
||||
return os.path.isdir(os.path.join(sysroot_root, sysroot_name))
|
||||
|
||||
|
||||
def GetAllPlatformConfigs(build_args):
|
||||
def GetAllPlatformConfigs(build_args, quiet=False):
|
||||
"""
|
||||
Return a map of directory name to GN args for the current platform.
|
||||
"""
|
||||
result = {}
|
||||
|
||||
if quiet:
|
||||
global _QUIET
|
||||
_QUIET = True
|
||||
|
||||
# Merged args without validation.
|
||||
args = GetMergedArgs(build_args)
|
||||
|
||||
|
@@ -1,95 +0,0 @@
|
||||
# Copyright (c) 2019 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
|
||||
from cef_api_hash import cef_api_hash
|
||||
from cef_parser import get_copyright
|
||||
from file_util import *
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def make_api_hash_header(cpp_header_dir):
|
||||
# calculate api hashes
|
||||
api_hash_calculator = cef_api_hash(cpp_header_dir, verbose=False)
|
||||
api_hash = api_hash_calculator.calculate()
|
||||
|
||||
result = get_copyright(full=True, translator=False) + \
|
||||
"""//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file was generated by the make_api_hash_header.py tool.
|
||||
//
|
||||
|
||||
#ifndef CEF_INCLUDE_API_HASH_H_
|
||||
#define CEF_INCLUDE_API_HASH_H_
|
||||
|
||||
#include "include/internal/cef_export.h"
|
||||
|
||||
// The API hash is created by analyzing CEF header files for C API type
|
||||
// definitions. The hash value will change when header files are modified in a
|
||||
// way that may cause binary incompatibility with other builds. The universal
|
||||
// hash value will change if any platform is affected whereas the platform hash
|
||||
// values will change only if that particular platform is affected.
|
||||
#define CEF_API_HASH_UNIVERSAL "$UNIVERSAL$"
|
||||
#if defined(OS_WIN)
|
||||
#define CEF_API_HASH_PLATFORM "$WINDOWS$"
|
||||
#elif defined(OS_MAC)
|
||||
#define CEF_API_HASH_PLATFORM "$MAC$"
|
||||
#elif defined(OS_LINUX)
|
||||
#define CEF_API_HASH_PLATFORM "$LINUX$"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
///
|
||||
// Returns CEF API hashes for the libcef library. The returned string is owned
|
||||
// by the library and should not be freed. The |entry| parameter describes which
|
||||
// hash value will be returned:
|
||||
// 0 - CEF_API_HASH_PLATFORM
|
||||
// 1 - CEF_API_HASH_UNIVERSAL
|
||||
// 2 - CEF_COMMIT_HASH (from cef_version.h)
|
||||
///
|
||||
CEF_EXPORT const char* cef_api_hash(int entry);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // CEF_INCLUDE_API_HASH_H_
|
||||
"""
|
||||
|
||||
# Substitute hash values for placeholders.
|
||||
for platform, value in api_hash.items():
|
||||
result = result.replace('$%s$' % platform.upper(), value)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def write_api_hash_header(output, cpp_header_dir):
|
||||
output = os.path.abspath(output)
|
||||
result = make_api_hash_header(cpp_header_dir)
|
||||
ret = write_file_if_changed(output, result)
|
||||
|
||||
# Also write to |cpp_header_dir| if a different path from |output|, since we
|
||||
# need to commit the hash header for cef_version.py to correctly calculate the
|
||||
# version number based on git history.
|
||||
header_path = os.path.abspath(
|
||||
os.path.join(cpp_header_dir, os.path.basename(output)))
|
||||
if (output != header_path):
|
||||
write_file_if_changed(header_path, result)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def main(argv):
|
||||
if len(argv) < 3:
|
||||
print(("Usage:\n %s <output_filename> <cpp_header_dir>" % argv[0]))
|
||||
sys.exit(-1)
|
||||
write_api_hash_header(argv[1], argv[2])
|
||||
|
||||
|
||||
if '__main__' == __name__:
|
||||
main(sys.argv)
|
130
tools/make_api_versions_header.py
Normal file
130
tools/make_api_versions_header.py
Normal file
@@ -0,0 +1,130 @@
|
||||
# Copyright (c) 2024 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
|
||||
from cef_parser import get_copyright
|
||||
from file_util import write_file_if_changed
|
||||
from version_util import read_version_files
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def make_api_versions_header(json):
|
||||
result = get_copyright(full=True, translator=False) + \
|
||||
"""//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file was generated by the make_api_versions_header.py tool. Versions
|
||||
// are managed using the version_manager.py tool. For usage details see
|
||||
// https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
|
||||
//
|
||||
|
||||
#ifndef CEF_INCLUDE_CEF_API_VERSIONS_H_
|
||||
#define CEF_INCLUDE_CEF_API_VERSIONS_H_
|
||||
|
||||
#include "include/base/cef_build.h"
|
||||
"""
|
||||
|
||||
for version, hashes in json['hashes'].items():
|
||||
version_part = """
|
||||
// $COMMENT$
|
||||
#define CEF_API_VERSION_$VER$ $VER$
|
||||
#define CEF_API_HASH_$VER$_UNIVERSAL "$UNIVERSAL$"
|
||||
#if defined(OS_WIN)
|
||||
#define CEF_API_HASH_$VER$_PLATFORM "$WINDOWS$"
|
||||
#elif defined(OS_MAC)
|
||||
#define CEF_API_HASH_$VER$_PLATFORM "$MAC$"
|
||||
#elif defined(OS_LINUX)
|
||||
#define CEF_API_HASH_$VER$_PLATFORM "$LINUX$"
|
||||
#endif
|
||||
""".replace('$VER$', version)
|
||||
|
||||
# Substitute hash values for placeholders.
|
||||
for key, value in hashes.items():
|
||||
version_part = version_part.replace('$%s$' % key.upper(), value)
|
||||
|
||||
result += version_part
|
||||
|
||||
result += \
|
||||
"""
|
||||
// Oldest supported CEF version.
|
||||
#define CEF_API_VERSION_MIN CEF_API_VERSION_$MIN$
|
||||
|
||||
// Newest supported CEF version.
|
||||
#define CEF_API_VERSION_LAST CEF_API_VERSION_$LAST$
|
||||
|
||||
#endif // CEF_INCLUDE_CEF_API_VERSIONS_H_
|
||||
""".replace('$LAST$', json['last']).replace('$MIN$', json['min'])
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def make_api_versions_inc(json):
|
||||
result = get_copyright(full=False, translator=False) + \
|
||||
"""//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file was generated by the make_api_versions_header.py tool.
|
||||
//
|
||||
|
||||
namespace {
|
||||
|
||||
struct ApiVersionHash {
|
||||
int version;
|
||||
const char* const universal;
|
||||
const char* const platform;
|
||||
};
|
||||
|
||||
const ApiVersionHash kApiVersionHashes[] = {"""
|
||||
|
||||
for version, hashes in json['hashes'].items():
|
||||
result += """
|
||||
{$VER$, CEF_API_HASH_$VER$_UNIVERSAL, CEF_API_HASH_$VER$_PLATFORM},""".replace(
|
||||
'$VER$', version)
|
||||
|
||||
result += \
|
||||
"""
|
||||
};
|
||||
|
||||
const size_t kApiVersionHashesSize = std::size(kApiVersionHashes);
|
||||
|
||||
} // namespace
|
||||
"""
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def write_api_versions(out_header_file, out_inc_file, json):
|
||||
out_file = os.path.abspath(out_header_file)
|
||||
result = make_api_versions_header(json)
|
||||
if not bool(result):
|
||||
sys.stderr.write('Failed to create %s\n' % out_file)
|
||||
sys.exit(1)
|
||||
retval1 = write_file_if_changed(out_file, result)
|
||||
|
||||
out_file = os.path.abspath(out_inc_file)
|
||||
result = make_api_versions_inc(json)
|
||||
if not bool(result):
|
||||
sys.stderr.write('Failed to create %s\n' % out_file)
|
||||
sys.exit(1)
|
||||
retval2 = write_file_if_changed(out_file, result)
|
||||
|
||||
return retval1 or retval2
|
||||
|
||||
|
||||
def main(argv):
|
||||
if len(argv) < 5:
|
||||
print(
|
||||
"Usage:\n %s <output_header_file> <output_inc_file> <api_versions_file> <api_untracked_file>"
|
||||
% argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
json, initialized = \
|
||||
read_version_files(argv[3], argv[4], True, combine=True)
|
||||
if not write_api_versions(argv[1], argv[2], json):
|
||||
print('Nothing done')
|
||||
|
||||
|
||||
if '__main__' == __name__:
|
||||
main(sys.argv)
|
@@ -8,33 +8,41 @@ from cef_parser import *
|
||||
|
||||
def make_capi_global_funcs(funcs, defined_names, translate_map, indent):
|
||||
result = ''
|
||||
first = True
|
||||
for func in funcs:
|
||||
comment = func.get_comment()
|
||||
if first or len(comment) > 0:
|
||||
result += '\n' + format_comment(comment, indent, translate_map)
|
||||
pre, post = get_version_surround(func)
|
||||
result += '\n' + pre
|
||||
if len(comment) > 0:
|
||||
result += format_comment(comment, indent, translate_map)
|
||||
if func.get_retval().get_type().is_result_string():
|
||||
result += indent + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
|
||||
result += indent + 'CEF_EXPORT ' + func.get_capi_proto(defined_names) + ';\n'
|
||||
if first:
|
||||
first = False
|
||||
result += indent + 'CEF_EXPORT ' + func.get_capi_proto(
|
||||
defined_names) + ';\n' + post
|
||||
return result
|
||||
|
||||
|
||||
def make_capi_member_funcs(funcs, defined_names, translate_map, indent):
|
||||
result = ''
|
||||
first = True
|
||||
for func in funcs:
|
||||
comment = func.get_comment()
|
||||
if first or len(comment) > 0:
|
||||
result += '\n' + format_comment(comment, indent, translate_map)
|
||||
pre, post = get_version_surround(func)
|
||||
result += '\n' + pre
|
||||
if len(comment) > 0:
|
||||
result += format_comment(comment, indent, translate_map)
|
||||
if func.get_retval().get_type().is_result_string():
|
||||
result += indent + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
|
||||
parts = func.get_capi_parts()
|
||||
result += indent+parts['retval']+' (CEF_CALLBACK *'+parts['name']+ \
|
||||
')('+', '.join(parts['args'])+');\n'
|
||||
if first:
|
||||
first = False
|
||||
result += indent + parts['retval'] + ' (CEF_CALLBACK *' + parts['name'] + \
|
||||
')(' + ', '.join(parts['args']) + ');\n'
|
||||
if len(post) > 0 and func.has_version_removed():
|
||||
if func.has_version_added():
|
||||
result += '#elif ' + get_version_check({
|
||||
'added': func.get_attrib('removed')
|
||||
})
|
||||
else:
|
||||
result += '#else'
|
||||
result += '\n' + indent + 'uintptr_t ' + parts['name'] + '_removed;\n'
|
||||
result += post
|
||||
return result
|
||||
|
||||
|
||||
@@ -61,13 +69,16 @@ def make_capi_header(header, filename):
|
||||
#define $GUARD$
|
||||
#pragma once
|
||||
|
||||
#if defined(BUILDING_CEF_SHARED)
|
||||
#error This file cannot be included DLL-side
|
||||
#endif
|
||||
|
||||
"""
|
||||
|
||||
# Protect against incorrect use of test headers.
|
||||
if filename.startswith('test/'):
|
||||
result += \
|
||||
"""#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \\
|
||||
!defined(UNIT_TEST)
|
||||
"""#if !defined(WRAPPING_CEF_SHARED) && !defined(UNIT_TEST)
|
||||
#error This file can be included for unit tests only
|
||||
#endif
|
||||
|
||||
@@ -78,7 +89,7 @@ def make_capi_header(header, filename):
|
||||
# identify all includes and forward declarations
|
||||
translated_includes = set([])
|
||||
internal_includes = set([])
|
||||
all_declares = set([])
|
||||
all_declares = {}
|
||||
for cls in classes:
|
||||
includes = cls.get_includes()
|
||||
for include in includes:
|
||||
@@ -87,7 +98,7 @@ def make_capi_header(header, filename):
|
||||
# translated CEF API headers.
|
||||
raise Exception('Disallowed include of %s.h from %s' % (include,
|
||||
filename))
|
||||
elif include.startswith('internal/'):
|
||||
elif include.startswith('internal/') or include == 'cef_api_hash':
|
||||
# internal/ headers may be C or C++. Include them as-is.
|
||||
internal_includes.add(include)
|
||||
else:
|
||||
@@ -97,7 +108,10 @@ def make_capi_header(header, filename):
|
||||
declare_cls = header.get_class(declare)
|
||||
if declare_cls is None:
|
||||
raise Exception('Unknown class: %s' % declare)
|
||||
all_declares.add(declare_cls.get_capi_name())
|
||||
capi_name = declare_cls.get_capi_name()
|
||||
if not capi_name in all_declares:
|
||||
all_declares[capi_name] = declare_cls.get_version_check() \
|
||||
if declare_cls.has_version() else None
|
||||
|
||||
# output translated includes
|
||||
if len(translated_includes) > 0:
|
||||
@@ -122,22 +136,39 @@ extern "C" {
|
||||
"""
|
||||
|
||||
# output forward declarations
|
||||
if len(all_declares) > 0:
|
||||
sorted_declares = sorted(all_declares)
|
||||
if bool(all_declares):
|
||||
sorted_declares = sorted(all_declares.keys())
|
||||
for declare in sorted_declares:
|
||||
cls_version_check = all_declares[declare]
|
||||
if not cls_version_check is None:
|
||||
result += '#if ' + cls_version_check + '\n'
|
||||
result += 'struct _' + declare + ';\n'
|
||||
if not cls_version_check is None:
|
||||
result += '#endif\n'
|
||||
|
||||
# output classes
|
||||
for cls in classes:
|
||||
pre, post = get_version_surround(cls, long=True)
|
||||
if len(pre) > 0:
|
||||
result += '\n' + pre
|
||||
|
||||
comment = cls.get_comment()
|
||||
add_comment = []
|
||||
if comment[-1] != '':
|
||||
add_comment.append('')
|
||||
add_comment.append('NOTE: This struct is allocated %s-side.' % \
|
||||
('client' if cls.is_client_side() else 'DLL'))
|
||||
add_comment.append('')
|
||||
|
||||
# virtual functions are inside the structure
|
||||
classname = cls.get_capi_name()
|
||||
result += '\n' + format_comment(cls.get_comment(), '', translate_map)
|
||||
result += '\n' + format_comment(comment + add_comment, '', translate_map)
|
||||
result += 'typedef struct _'+classname+' {\n'+\
|
||||
' ///\n'+\
|
||||
' /// Base structure.\n'+\
|
||||
' ///\n'+\
|
||||
' '+cls.get_parent_capi_name()+' base;\n'
|
||||
funcs = cls.get_virtual_funcs()
|
||||
funcs = cls.get_virtual_funcs(version_order=True)
|
||||
result += make_capi_member_funcs(funcs, defined_names, translate_map, ' ')
|
||||
result += '} ' + classname + ';\n\n'
|
||||
|
||||
@@ -149,6 +180,8 @@ extern "C" {
|
||||
result += make_capi_global_funcs(funcs, defined_names, translate_map,
|
||||
'') + '\n'
|
||||
|
||||
result += post
|
||||
|
||||
# output global functions
|
||||
funcs = header.get_funcs(filename)
|
||||
if len(funcs) > 0:
|
||||
|
189
tools/make_capi_versions_header.py
Normal file
189
tools/make_capi_versions_header.py
Normal file
@@ -0,0 +1,189 @@
|
||||
# Copyright (c) 2024 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
|
||||
from cef_parser import *
|
||||
import functools
|
||||
|
||||
|
||||
def _version_finder(header, name):
|
||||
cls = header.get_capi_class(name)
|
||||
if not cls is None:
|
||||
return cls.get_capi_name(first_version=True)
|
||||
return name
|
||||
|
||||
|
||||
def make_capi_global_funcs(version, version_finder, funcs, defined_names):
|
||||
result = ''
|
||||
for func in funcs:
|
||||
result += 'CEF_EXPORT ' + func.get_capi_proto(
|
||||
defined_names, version=version, version_finder=version_finder) + ';\n'
|
||||
return result
|
||||
|
||||
|
||||
def make_capi_member_funcs(version, version_finder, funcs, defined_names,
|
||||
translate_map, indent):
|
||||
result = ''
|
||||
for func in funcs:
|
||||
parts = func.get_capi_parts(version=version, version_finder=version_finder)
|
||||
if func.removed_at_version(version):
|
||||
result += indent + 'uintptr_t ' + parts['name'] + '_removed;\n'
|
||||
else:
|
||||
result += indent + parts['retval'] + ' (CEF_CALLBACK *' + parts['name'] + \
|
||||
')(' + ', '.join(parts['args']) + ');\n'
|
||||
return result
|
||||
|
||||
|
||||
def make_capi_versions_header(header, filename):
|
||||
# structure names that have already been defined
|
||||
defined_names = header.get_defined_structs()
|
||||
|
||||
# map of strings that will be changed in C++ comments
|
||||
translate_map = header.get_capi_translations()
|
||||
|
||||
# header string
|
||||
result = get_copyright(full=True, translator=False) + \
|
||||
"""//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file was generated by the CEF translator tool and should not edited
|
||||
// by hand. See the translator.README.txt file in the tools directory for
|
||||
// more information.
|
||||
//
|
||||
// $hash=$$HASH$$$
|
||||
//
|
||||
|
||||
#ifndef $GUARD$
|
||||
#define $GUARD$
|
||||
#pragma once
|
||||
|
||||
#if !defined(BUILDING_CEF_SHARED)
|
||||
#error This file can be included DLL-side only
|
||||
#endif
|
||||
|
||||
"""
|
||||
|
||||
classes = header.get_classes(filename)
|
||||
|
||||
# identify all includes and forward declarations
|
||||
translated_includes = set()
|
||||
internal_includes = set()
|
||||
all_declares = set()
|
||||
for cls in classes:
|
||||
includes = cls.get_includes()
|
||||
for include in includes:
|
||||
if include.startswith('base/'):
|
||||
# base/ headers are C++. They should not be included by
|
||||
# translated CEF API headers.
|
||||
raise Exception('Disallowed include of %s.h from %s' % (include,
|
||||
filename))
|
||||
elif include.startswith('internal/') or include == 'cef_api_hash':
|
||||
# internal/ headers may be C or C++. Include them as-is.
|
||||
internal_includes.add(include)
|
||||
else:
|
||||
translated_includes.add(include)
|
||||
declares = cls.get_forward_declares()
|
||||
for declare in declares:
|
||||
declare_cls = header.get_class(declare)
|
||||
if declare_cls is None:
|
||||
raise Exception('Unknown class: %s' % declare)
|
||||
for version in declare_cls.get_all_versions():
|
||||
all_declares.add(declare_cls.get_capi_name(version=version))
|
||||
|
||||
# output translated includes
|
||||
if len(translated_includes) > 0:
|
||||
sorted_includes = sorted(translated_includes)
|
||||
for include in sorted_includes:
|
||||
suffix = '_versions' if not include in ('cef_base',) else ''
|
||||
result += '#include "include/capi/' + include + '_capi' + suffix + '.h"\n'
|
||||
else:
|
||||
result += '#include "include/capi/cef_base_capi.h"\n'
|
||||
|
||||
# output internal includes
|
||||
if len(internal_includes) > 0:
|
||||
sorted_includes = sorted(internal_includes)
|
||||
for include in sorted_includes:
|
||||
result += '#include "include/' + include + '.h"\n'
|
||||
|
||||
result += \
|
||||
"""
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
"""
|
||||
|
||||
# output forward declarations
|
||||
if bool(all_declares):
|
||||
for declare in sorted(all_declares):
|
||||
result += 'struct _' + declare + ';\n'
|
||||
result += '\n'
|
||||
|
||||
version_finder = functools.partial(_version_finder, header)
|
||||
|
||||
# output classes
|
||||
for cls in classes:
|
||||
for version in cls.get_all_versions():
|
||||
# virtual functions are inside the structure
|
||||
classname = cls.get_capi_name(version=version)
|
||||
result += 'typedef struct _'+classname+' {\n'+\
|
||||
' '+cls.get_parent_capi_name(version=version)+' base;\n'
|
||||
funcs = cls.get_virtual_funcs(version_order=True, version=version)
|
||||
result += make_capi_member_funcs(version, version_finder, funcs,
|
||||
defined_names, translate_map, ' ')
|
||||
result += '} ' + classname + ';\n\n'
|
||||
|
||||
defined_names.append(classname)
|
||||
|
||||
# static functions become global
|
||||
funcs = cls.get_static_funcs()
|
||||
if len(funcs) > 0:
|
||||
result += make_capi_global_funcs(version, version_finder, funcs,
|
||||
defined_names) + '\n'
|
||||
|
||||
# output global functions
|
||||
funcs = header.get_funcs(filename)
|
||||
if len(funcs) > 0:
|
||||
result += make_capi_global_funcs(None, version_finder, funcs,
|
||||
defined_names) + '\n'
|
||||
|
||||
# footer string
|
||||
result += \
|
||||
"""#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // $GUARD$
|
||||
"""
|
||||
|
||||
# add the guard string
|
||||
guard = 'CEF_INCLUDE_CAPI_' + \
|
||||
filename.replace('/', '_').replace('.', '_capi_versions_').upper() + '_'
|
||||
result = result.replace('$GUARD$', guard)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def write_capi_versions_header(header, header_dir, filename):
|
||||
file = get_capi_file_name(os.path.join(header_dir, filename), versions=True)
|
||||
newcontents = make_capi_versions_header(header, filename)
|
||||
return (file, newcontents)
|
||||
|
||||
|
||||
# test the module
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
# verify that the correct number of command-line arguments are provided
|
||||
if len(sys.argv) < 2:
|
||||
sys.stderr.write('Usage: ' + sys.argv[0] + ' <infile>\n')
|
||||
sys.exit()
|
||||
|
||||
# create the header object
|
||||
header = obj_header()
|
||||
header.add_file(sys.argv[1])
|
||||
|
||||
# dump the result to stdout
|
||||
filename = os.path.split(sys.argv[1])[1]
|
||||
sys.stdout.write(make_capi_versions_header(header, filename))
|
@@ -20,8 +20,6 @@ def make_cpptoc_header(header, clsname):
|
||||
defname += get_capi_name(clsname[3:], False)
|
||||
defname = defname.upper()
|
||||
|
||||
capiname = cls.get_capi_name()
|
||||
|
||||
result = get_copyright()
|
||||
|
||||
result += '#ifndef CEF_LIBCEF_DLL_CPPTOC_'+defname+'_CPPTOC_H_\n'+ \
|
||||
@@ -41,9 +39,11 @@ def make_cpptoc_header(header, clsname):
|
||||
#endif
|
||||
"""
|
||||
|
||||
with_versions = dllside
|
||||
|
||||
# include the headers for this class
|
||||
result += '\n#include "include/'+cls.get_file_name()+'"\n' \
|
||||
'#include "include/capi/'+cls.get_capi_file_name()+'"\n'
|
||||
'#include "include/capi/'+cls.get_capi_file_name(versions=with_versions)+'"\n'
|
||||
|
||||
# include headers for any forward declared classes that are not in the same file
|
||||
declares = cls.get_forward_declares()
|
||||
@@ -51,7 +51,7 @@ def make_cpptoc_header(header, clsname):
|
||||
dcls = header.get_class(declare)
|
||||
if dcls.get_file_name() != cls.get_file_name():
|
||||
result += '#include "include/'+dcls.get_file_name()+'"\n' \
|
||||
'#include "include/capi/'+dcls.get_capi_file_name()+'"\n'
|
||||
'#include "include/capi/'+dcls.get_capi_file_name(versions=with_versions)+'"\n'
|
||||
|
||||
base_class_name = header.get_base_class_name(clsname)
|
||||
base_scoped = True if base_class_name == 'CefBaseScoped' else False
|
||||
@@ -63,19 +63,78 @@ def make_cpptoc_header(header, clsname):
|
||||
template_class = 'CefCppToCRefCounted'
|
||||
|
||||
result += '#include "libcef_dll/cpptoc/' + template_file + '"'
|
||||
result += '\n\n// Wrap a C++ class with a C structure.\n'
|
||||
|
||||
if dllside:
|
||||
result += '// This class may be instantiated and accessed DLL-side only.\n'
|
||||
if with_versions:
|
||||
pre = post = ''
|
||||
else:
|
||||
result += '// This class may be instantiated and accessed wrapper-side only.\n'
|
||||
pre, post = get_version_surround(cls, long=True)
|
||||
if len(pre) > 0:
|
||||
result += '\n\n' + pre.strip()
|
||||
|
||||
result += 'class '+clsname+'CppToC\n'+ \
|
||||
' : public ' + template_class + '<'+clsname+'CppToC, '+clsname+', '+capiname+'> {\n'+ \
|
||||
' public:\n'+ \
|
||||
' '+clsname+'CppToC();\n'+ \
|
||||
' virtual ~'+clsname+'CppToC();\n'+ \
|
||||
'};\n\n'
|
||||
result += '\n\n'
|
||||
|
||||
versions = cls.get_all_versions() if with_versions else (None,)
|
||||
|
||||
for version in versions:
|
||||
result += '// Wrap a C++ class with a C structure%s.\n' % \
|
||||
('' if version is None else ' at API version %d' % version)
|
||||
if dllside:
|
||||
result += '// This class may be instantiated and accessed DLL-side only.\n'
|
||||
else:
|
||||
result += '// This class may be instantiated and accessed wrapper-side only.\n'
|
||||
|
||||
capiname = cls.get_capi_name(version=version)
|
||||
if version is None:
|
||||
typename = clsname + 'CppToC'
|
||||
else:
|
||||
typename = clsname + '_%d_CppToC' % version
|
||||
|
||||
result += 'class '+typename+'\n'+ \
|
||||
' : public ' + template_class + '<'+typename+', '+clsname+', '+capiname+'> {\n'+ \
|
||||
' public:\n'+ \
|
||||
' '+typename+'();\n'+ \
|
||||
' virtual ~'+typename+'();\n'+ \
|
||||
'};\n\n'
|
||||
|
||||
typename = clsname + 'CppToC'
|
||||
if len(versions) > 1:
|
||||
result += '// Helpers to return objects at the globally configured API version.\n'
|
||||
structname = cls.get_capi_name(version=versions[0])
|
||||
if base_scoped:
|
||||
result += structname + '* ' + typename + '_WrapOwn(CefOwnPtr<' + clsname + '> c);\n' + \
|
||||
'std::pair<CefOwnPtr<CefBaseScoped>, '+ structname + '*> ' + typename + '_WrapRaw(CefRawPtr<' + clsname + '> c);\n' + \
|
||||
'CefOwnPtr<' + clsname + '> ' + typename + '_UnwrapOwn('+ structname + '* s);\n' + \
|
||||
'CefRawPtr<' + clsname + '> ' + typename + '_UnwrapRaw('+ structname + '* s);\n' + \
|
||||
'CefBaseScoped* ' + typename + '_GetWrapper('+ structname + '* s);\n\n'
|
||||
else:
|
||||
result += structname + '* ' + typename + '_Wrap(CefRefPtr<' + clsname + '> c);\n' + \
|
||||
'CefRefPtr<' + clsname + '> ' + typename + '_Unwrap('+ structname + '* s);\n\n'
|
||||
else:
|
||||
if versions[0] is None:
|
||||
targetname = clsname + 'CppToC'
|
||||
structname = cls.get_capi_name()
|
||||
else:
|
||||
targetname = clsname + '_%d_CppToC' % versions[0]
|
||||
structname = cls.get_capi_name(version=versions[0])
|
||||
if base_scoped:
|
||||
result += 'constexpr auto ' + typename + '_WrapOwn = ' + targetname + '::WrapOwn;\n' + \
|
||||
'constexpr auto ' + typename + '_WrapRaw = ' + targetname + '::WrapRaw;\n' + \
|
||||
'constexpr auto ' + typename + '_UnwrapOwn = ' + targetname + '::UnwrapOwn;\n' + \
|
||||
'constexpr auto ' + typename + '_UnwrapRaw = ' + targetname + '::UnwrapRaw;\n' + \
|
||||
'constexpr auto ' + typename + '_GetWrapper = ' + targetname + '::GetWrapper;\n\n'
|
||||
else:
|
||||
result += 'constexpr auto ' + typename + '_Wrap = ' + targetname + '::Wrap;\n' + \
|
||||
'constexpr auto ' + typename + '_Unwrap = ' + targetname + '::Unwrap;\n\n'
|
||||
|
||||
if base_scoped:
|
||||
result += 'inline ' + structname + '* ' + typename + '_WrapRawAndRelease(CefRawPtr<' + clsname + '> c) {\n' + \
|
||||
' auto [ownerPtr, structPtr] = ' + typename + '_WrapRaw(c);\n' + \
|
||||
' ownerPtr.release();\n' + \
|
||||
' return structPtr;\n' + \
|
||||
'}\n\n'
|
||||
|
||||
if len(post) > 0:
|
||||
result += post + '\n'
|
||||
|
||||
result += '#endif // CEF_LIBCEF_DLL_CPPTOC_' + defname + '_CPPTOC_H_'
|
||||
|
||||
|
@@ -4,6 +4,8 @@
|
||||
|
||||
from __future__ import absolute_import
|
||||
from cef_parser import *
|
||||
import copy
|
||||
import functools
|
||||
|
||||
|
||||
def make_cpptoc_impl_proto(name, func, parts):
|
||||
@@ -16,27 +18,37 @@ def make_cpptoc_impl_proto(name, func, parts):
|
||||
return proto
|
||||
|
||||
|
||||
def make_cpptoc_function_impl_existing(cls, name, func, impl, defined_names):
|
||||
def make_cpptoc_function_impl_existing(cls, name, func, impl, defined_names,
|
||||
version, version_finder):
|
||||
notify(name + ' has manual edits')
|
||||
|
||||
# retrieve the C API prototype parts
|
||||
parts = func.get_capi_parts(defined_names, True)
|
||||
parts = func.get_capi_parts(
|
||||
defined_names, True, version=version, version_finder=version_finder)
|
||||
|
||||
changes = format_translation_changes(impl, parts)
|
||||
if len(changes) > 0:
|
||||
notify(name + ' prototype changed')
|
||||
|
||||
return make_cpptoc_impl_proto(
|
||||
name, func, parts) + '{' + changes + impl['body'] + '\n}\n\n'
|
||||
return make_cpptoc_impl_proto(name, func,
|
||||
parts) + '{' + changes + impl['body'] + '\n}\n'
|
||||
|
||||
|
||||
def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
|
||||
def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped,
|
||||
version, version_finder):
|
||||
if not version is None and isinstance(func, obj_function_virtual) and \
|
||||
not func.exists_at_version(version):
|
||||
raise Exception(
|
||||
'Attempting to generate non-existing function %s at version %d' %
|
||||
(name, version))
|
||||
|
||||
# Special handling for the cef_shutdown global function.
|
||||
is_cef_shutdown = name == 'cef_shutdown' and isinstance(
|
||||
func.parent, obj_header)
|
||||
|
||||
# retrieve the C API prototype parts
|
||||
parts = func.get_capi_parts(defined_names, True)
|
||||
parts = func.get_capi_parts(
|
||||
defined_names, True, version=version, version_finder=version_finder)
|
||||
result = make_cpptoc_impl_proto(name, func, parts) + ' {'
|
||||
|
||||
if isinstance(func.parent, obj_class) and \
|
||||
@@ -219,31 +231,31 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
|
||||
elif arg_type == 'refptr_same' or arg_type == 'refptr_diff':
|
||||
ptr_class = arg.get_type().get_ptr_type()
|
||||
if arg_type == 'refptr_same':
|
||||
params.append(ptr_class + 'CppToC::Unwrap(' + arg_name + ')')
|
||||
params.append(ptr_class + 'CppToC_Unwrap(' + arg_name + ')')
|
||||
else:
|
||||
params.append(ptr_class + 'CToCpp::Wrap(' + arg_name + ')')
|
||||
params.append(ptr_class + 'CToCpp_Wrap(' + arg_name + ')')
|
||||
elif arg_type == 'ownptr_same' or arg_type == 'rawptr_same':
|
||||
ptr_class = arg.get_type().get_ptr_type()
|
||||
if arg_type == 'ownptr_same':
|
||||
params.append(ptr_class + 'CppToC::UnwrapOwn(' + arg_name + ')')
|
||||
params.append(ptr_class + 'CppToC_UnwrapOwn(' + arg_name + ')')
|
||||
else:
|
||||
params.append(ptr_class + 'CppToC::UnwrapRaw(' + arg_name + ')')
|
||||
params.append(ptr_class + 'CppToC_UnwrapRaw(' + arg_name + ')')
|
||||
elif arg_type == 'ownptr_diff' or arg_type == 'rawptr_diff':
|
||||
ptr_class = arg.get_type().get_ptr_type()
|
||||
result += comment+\
|
||||
'\n CefOwnPtr<'+ptr_class+'> '+arg_name+'Ptr('+ptr_class+'CToCpp::Wrap('+arg_name+'));'
|
||||
'\n CefOwnPtr<'+ptr_class+'> '+arg_name+'Ptr('+ptr_class+'CToCpp_Wrap('+arg_name+'));'
|
||||
if arg_type == 'ownptr_diff':
|
||||
params.append('std::move(' + arg_name + 'Ptr)')
|
||||
else:
|
||||
params.append(arg_name + 'Ptr.get()')
|
||||
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
|
||||
ptr_class = arg.get_type().get_ptr_type()
|
||||
ptr_class = ptr_class_u = arg.get_type().get_ptr_type()
|
||||
if arg_type == 'refptr_same_byref':
|
||||
assign = ptr_class + 'CppToC::Unwrap(*' + arg_name + ')'
|
||||
assign = ptr_class + 'CppToC_Unwrap(*' + arg_name + ')'
|
||||
else:
|
||||
assign = ptr_class + 'CToCpp::Wrap(*' + arg_name + ')'
|
||||
assign = ptr_class + 'CToCpp_Wrap(*' + arg_name + ')'
|
||||
result += comment+\
|
||||
'\n CefRefPtr<'+ptr_class+'> '+arg_name+'Ptr;'\
|
||||
'\n CefRefPtr<'+ptr_class_u+'> '+arg_name+'Ptr;'\
|
||||
'\n if ('+arg_name+' && *'+arg_name+') {'\
|
||||
'\n '+arg_name+'Ptr = '+assign+';'\
|
||||
'\n }'\
|
||||
@@ -273,10 +285,10 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
|
||||
assign = arg_name + '[i]?true:false'
|
||||
elif arg_type == 'refptr_vec_same_byref':
|
||||
ptr_class = arg.get_type().get_ptr_type()
|
||||
assign = ptr_class + 'CppToC::Unwrap(' + arg_name + '[i])'
|
||||
assign = ptr_class + 'CppToC_Unwrap(' + arg_name + '[i])'
|
||||
elif arg_type == 'refptr_vec_diff_byref':
|
||||
ptr_class = arg.get_type().get_ptr_type()
|
||||
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + '[i])'
|
||||
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i])'
|
||||
result += comment+\
|
||||
'\n std::vector<'+vec_type+' > '+arg_name+'List;'\
|
||||
'\n if ('+arg_name+'Count && *'+arg_name+'Count > 0 && '+arg_name+') {'\
|
||||
@@ -296,13 +308,13 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
|
||||
else:
|
||||
ptr_class = arg.get_type().get_ptr_type()
|
||||
if arg_type == 'refptr_vec_same_byref_const':
|
||||
assign = ptr_class + 'CppToC::Unwrap(' + arg_name + '[i])'
|
||||
assign = ptr_class + 'CppToC_Unwrap(' + arg_name + '[i])'
|
||||
elif arg_type == 'refptr_vec_diff_byref_const':
|
||||
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + '[i])'
|
||||
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i])'
|
||||
elif arg_type == 'rawptr_vec_same_byref_const':
|
||||
assign = ptr_class + 'CppToC::UnwrapRaw(' + arg_name + '[i])'
|
||||
assign = ptr_class + 'CppToC_UnwrapRaw(' + arg_name + '[i])'
|
||||
elif arg_type == 'rawptr_vec_diff_byref_const':
|
||||
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + '[i]).release()'
|
||||
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i]).release()'
|
||||
result += comment+\
|
||||
'\n std::vector<'+vec_type+' > '+arg_name+'List;'\
|
||||
'\n if ('+arg_name+'Count > 0) {'\
|
||||
@@ -334,13 +346,16 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
|
||||
if isinstance(func.parent, obj_class):
|
||||
# virtual and static class methods
|
||||
if isinstance(func, obj_function_virtual):
|
||||
ptr_class = cls.get_name()
|
||||
if not version_finder is None:
|
||||
ptr_class = version_finder(ptr_class, as_cpp=True)
|
||||
if cls.get_name() == func.parent.get_name():
|
||||
# virtual method for the current class
|
||||
result += func.parent.get_name() + 'CppToC::Get(self)->'
|
||||
# virtual method called for the current class
|
||||
result += ptr_class + 'CppToC::Get(self)->'
|
||||
else:
|
||||
# virtual method for a parent class
|
||||
result += cls.get_name(
|
||||
) + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name() + '*>(self))->'
|
||||
# virtual method called for a parent class
|
||||
result += ptr_class + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name(
|
||||
version) + '*>(self))->'
|
||||
else:
|
||||
result += func.parent.get_name() + '::'
|
||||
result += func.get_name() + '('
|
||||
@@ -382,9 +397,9 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
|
||||
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
|
||||
ptr_class = arg.get_type().get_ptr_type()
|
||||
if arg_type == 'refptr_same_byref':
|
||||
assign = ptr_class + 'CppToC::Wrap(' + arg_name + 'Ptr)'
|
||||
assign = ptr_class + 'CppToC_Wrap(' + arg_name + 'Ptr)'
|
||||
else:
|
||||
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + 'Ptr)'
|
||||
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + 'Ptr)'
|
||||
result += comment+\
|
||||
'\n if ('+arg_name+') {'\
|
||||
'\n if ('+arg_name+'Ptr.get()) {'\
|
||||
@@ -413,10 +428,10 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
|
||||
assign = arg_name + 'List[i]'
|
||||
elif arg_type == 'refptr_vec_same_byref':
|
||||
ptr_class = arg.get_type().get_ptr_type()
|
||||
assign = ptr_class + 'CppToC::Wrap(' + arg_name + 'List[i])'
|
||||
assign = ptr_class + 'CppToC_Wrap(' + arg_name + 'List[i])'
|
||||
elif arg_type == 'refptr_vec_diff_byref':
|
||||
ptr_class = arg.get_type().get_ptr_type()
|
||||
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + 'List[i])'
|
||||
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + 'List[i])'
|
||||
result += comment+\
|
||||
'\n if ('+arg_name+'Count && '+arg_name+') {'\
|
||||
'\n *'+arg_name+'Count = std::min('+arg_name+'List.size(), *'+arg_name+'Count);'\
|
||||
@@ -452,80 +467,121 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
|
||||
result += '\n return _retval.DetachToUserFree();'
|
||||
elif retval_type == 'refptr_same':
|
||||
ptr_class = retval.get_type().get_ptr_type()
|
||||
result += '\n return ' + ptr_class + 'CppToC::Wrap(_retval);'
|
||||
result += '\n return ' + ptr_class + 'CppToC_Wrap(_retval);'
|
||||
elif retval_type == 'refptr_diff':
|
||||
ptr_class = retval.get_type().get_ptr_type()
|
||||
result += '\n return ' + ptr_class + 'CToCpp::Unwrap(_retval);'
|
||||
result += '\n return ' + ptr_class + 'CToCpp_Unwrap(_retval);'
|
||||
elif retval_type == 'ownptr_same':
|
||||
ptr_class = retval.get_type().get_ptr_type()
|
||||
result += '\n return ' + ptr_class + 'CppToC::WrapOwn(std::move(_retval));'
|
||||
result += '\n return ' + ptr_class + 'CppToC_WrapOwn(std::move(_retval));'
|
||||
elif retval_type == 'ownptr_diff':
|
||||
ptr_class = retval.get_type().get_ptr_type()
|
||||
result += '\n return ' + ptr_class + 'CToCpp::UnwrapOwn(std::move(_retval));'
|
||||
result += '\n return ' + ptr_class + 'CToCpp_UnwrapOwn(std::move(_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_cpptoc_function_impl(cls, funcs, existing, prefixname, defined_names,
|
||||
base_scoped):
|
||||
def make_cpptoc_function_impl(cls, funcs, existing, prefixname, suffixname,
|
||||
defined_names, base_scoped, version,
|
||||
version_finder):
|
||||
impl = ''
|
||||
|
||||
customized = False
|
||||
|
||||
for func in funcs:
|
||||
if not version is None and isinstance(func, obj_function_virtual) and \
|
||||
not func.exists_at_version(version):
|
||||
continue
|
||||
|
||||
name = func.get_capi_name()
|
||||
if not prefixname is None:
|
||||
name = prefixname + '_' + func.get_capi_name()
|
||||
name = prefixname + '_' + name
|
||||
if not suffixname is None:
|
||||
name += '_' + suffixname
|
||||
|
||||
if version is None:
|
||||
pre, post = get_version_surround(func, long=True)
|
||||
else:
|
||||
name = func.get_capi_name()
|
||||
pre = post = ''
|
||||
|
||||
value = get_next_function_impl(existing, name)
|
||||
if not value is None \
|
||||
and value['body'].find('// AUTO-GENERATED CONTENT') < 0:
|
||||
# an implementation exists that was not auto-generated
|
||||
impl += make_cpptoc_function_impl_existing(cls, name, func, value,
|
||||
defined_names)
|
||||
customized = True
|
||||
impl += pre + make_cpptoc_function_impl_existing(
|
||||
cls, name, func, value, defined_names, version,
|
||||
version_finder) + post + '\n'
|
||||
else:
|
||||
impl += make_cpptoc_function_impl_new(cls, name, func, defined_names,
|
||||
base_scoped)
|
||||
impl += pre + make_cpptoc_function_impl_new(
|
||||
cls, name, func, defined_names, 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_cpptoc_virtual_function_impl(header, cls, existing, prefixname,
|
||||
defined_names, base_scoped):
|
||||
funcs = []
|
||||
funcs.extend(cls.get_virtual_funcs())
|
||||
suffixname, defined_names, base_scoped,
|
||||
version, version_finder):
|
||||
# don't modify the original list
|
||||
funcs = copy.copy(cls.get_virtual_funcs(version=version))
|
||||
cur_cls = cls
|
||||
while True:
|
||||
parent_name = cur_cls.get_parent_name()
|
||||
if is_base_class(parent_name):
|
||||
break
|
||||
else:
|
||||
parent_cls = header.get_class(parent_name, defined_names)
|
||||
parent_cls = header.get_class(parent_name)
|
||||
if parent_cls is None:
|
||||
raise Exception('Class does not exist: ' + parent_name)
|
||||
funcs.extend(parent_cls.get_virtual_funcs())
|
||||
cur_cls = header.get_class(parent_name, defined_names)
|
||||
defined_names.append(parent_cls.get_capi_name(version))
|
||||
funcs.extend(parent_cls.get_virtual_funcs(version=version))
|
||||
cur_cls = header.get_class(parent_name)
|
||||
defined_names.append(cur_cls.get_capi_name(version))
|
||||
|
||||
return make_cpptoc_function_impl(cls, funcs, existing, prefixname,
|
||||
defined_names, base_scoped)
|
||||
return make_cpptoc_function_impl(cls, funcs, existing, prefixname, suffixname,
|
||||
defined_names, base_scoped, version,
|
||||
version_finder)
|
||||
|
||||
|
||||
def make_cpptoc_virtual_function_assignment_block(funcs, offset, prefixname):
|
||||
def make_cpptoc_virtual_function_assignment_block(cls, offset, prefixname,
|
||||
suffixname, version):
|
||||
impl = ''
|
||||
|
||||
funcs = cls.get_virtual_funcs(version_order=True, version=version)
|
||||
|
||||
for func in funcs:
|
||||
name = func.get_capi_name()
|
||||
impl += ' GetStruct()->' + offset + name + ' = ' + prefixname + '_' + name + ';\n'
|
||||
# should only include methods directly declared in the current class
|
||||
assert func.parent.get_name() == cls.get_name(), func.get_name()
|
||||
if version is None:
|
||||
pre, post = get_version_surround(func)
|
||||
else:
|
||||
if func.removed_at_version(version):
|
||||
continue
|
||||
pre = post = ''
|
||||
name = oname = func.get_capi_name()
|
||||
if not prefixname is None:
|
||||
name = prefixname + '_' + name
|
||||
if not suffixname is None:
|
||||
name += '_' + suffixname
|
||||
impl += pre + ' GetStruct()->' + offset + oname + ' = ' + name + ';\n' + post
|
||||
return impl
|
||||
|
||||
|
||||
def make_cpptoc_virtual_function_assignment(header, cls, prefixname,
|
||||
defined_names):
|
||||
impl = make_cpptoc_virtual_function_assignment_block(cls.get_virtual_funcs(),
|
||||
'', prefixname)
|
||||
def make_cpptoc_virtual_function_assignment(header, cls, prefixname, suffixname,
|
||||
defined_names, version,
|
||||
version_finder):
|
||||
impl = make_cpptoc_virtual_function_assignment_block(cls, '', prefixname,
|
||||
suffixname, version)
|
||||
|
||||
cur_cls = cls
|
||||
offset = ''
|
||||
@@ -535,17 +591,19 @@ def make_cpptoc_virtual_function_assignment(header, cls, prefixname,
|
||||
if is_base_class(parent_name):
|
||||
break
|
||||
else:
|
||||
parent_cls = header.get_class(parent_name, defined_names)
|
||||
parent_cls = header.get_class(parent_name)
|
||||
if parent_cls is None:
|
||||
raise Exception('Class does not exist: ' + parent_name)
|
||||
defined_names.append(parent_cls.get_capi_name(version))
|
||||
impl += make_cpptoc_virtual_function_assignment_block(
|
||||
parent_cls.get_virtual_funcs(), offset, prefixname)
|
||||
cur_cls = header.get_class(parent_name, defined_names)
|
||||
parent_cls, offset, prefixname, suffixname, version)
|
||||
cur_cls = header.get_class(parent_name)
|
||||
defined_names.append(cur_cls.get_capi_name(version))
|
||||
|
||||
return impl
|
||||
|
||||
|
||||
def make_cpptoc_unwrap_derived(header, cls, base_scoped):
|
||||
def make_cpptoc_unwrap_derived(header, cls, base_scoped, version):
|
||||
# identify all classes that derive from cls
|
||||
derived_classes = []
|
||||
cur_clsname = cls.get_name()
|
||||
@@ -561,39 +619,193 @@ def make_cpptoc_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 '+clsname+'CppToC::UnwrapOwn(reinterpret_cast<'+\
|
||||
get_capi_name(clsname, True)+'*>(s));\n'+\
|
||||
' }\n'
|
||||
impl[1] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
|
||||
' return '+clsname+'CppToC::UnwrapRaw(reinterpret_cast<'+\
|
||||
get_capi_name(clsname, True)+'*>(s));\n'+\
|
||||
' }\n'
|
||||
derived_cls = header.get_class(clsname)
|
||||
if version is None:
|
||||
capiname = derived_cls.get_capi_name()
|
||||
pre, post = get_version_surround(derived_cls)
|
||||
else:
|
||||
if not derived_cls.exists_at_version(version):
|
||||
continue
|
||||
capiname = derived_cls.get_capi_name(first_version=True)
|
||||
pre = post = ''
|
||||
|
||||
impl[0] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
|
||||
' return '+clsname+'CppToC_UnwrapOwn(reinterpret_cast<'+capiname+'*>(s));\n'+\
|
||||
' }\n' + post
|
||||
impl[1] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
|
||||
' return '+clsname+'CppToC_UnwrapRaw(reinterpret_cast<'+capiname+'*>(s));\n'+\
|
||||
' }\n' + post
|
||||
else:
|
||||
impl = ''
|
||||
for clsname in derived_classes:
|
||||
impl += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
|
||||
' return '+clsname+'CppToC::Unwrap(reinterpret_cast<'+\
|
||||
get_capi_name(clsname, True)+'*>(s));\n'+\
|
||||
' }\n'
|
||||
derived_cls = header.get_class(clsname)
|
||||
if version is None:
|
||||
capiname = derived_cls.get_capi_name()
|
||||
pre, post = get_version_surround(derived_cls)
|
||||
else:
|
||||
if not derived_cls.exists_at_version(version):
|
||||
continue
|
||||
capiname = derived_cls.get_capi_name(first_version=True)
|
||||
pre = post = ''
|
||||
|
||||
impl += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
|
||||
' return '+clsname+'CppToC_Unwrap(reinterpret_cast<'+capiname+'*>(s));\n'+\
|
||||
' }\n' + post
|
||||
return impl
|
||||
|
||||
|
||||
def make_cpptoc_version_wrappers(header, cls, base_scoped, versions):
|
||||
assert len(versions) > 0
|
||||
|
||||
clsname = cls.get_name()
|
||||
typename = clsname + 'CppToC'
|
||||
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 += structname + '* ' + typename + '_WrapOwn(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 + '_CppToC::WrapOwn(std::move(c));\n'
|
||||
else:
|
||||
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CppToC::WrapOwn(std::move(c)));\n'
|
||||
impl += ' }\n'
|
||||
|
||||
impl += ' ' + notreached + '\n'+ \
|
||||
'}\n\n' + \
|
||||
'std::pair<CefOwnPtr<CefBaseScoped>, '+ structname + '*> ' + typename + '_WrapRaw(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 + '_CppToC::WrapRaw(std::move(c));\n'
|
||||
else:
|
||||
impl += ' auto [ownPtr, structPtr] = ' + clsname + '_' + vstr + '_CppToC::WrapRaw(std::move(c));\n' + \
|
||||
' return std::make_pair(std::move(ownPtr), reinterpret_cast<' + structname + '*>(structPtr));\n'
|
||||
impl += ' }\n'
|
||||
|
||||
impl += ' ' + notreached + '\n'+ \
|
||||
'}\n\n' + \
|
||||
'CefOwnPtr<' + clsname + '> ' + typename + '_UnwrapOwn('+ 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 + '_CppToC::UnwrapOwn(s);\n'
|
||||
else:
|
||||
impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapOwn(reinterpret_cast<' + cls.get_capi_name(
|
||||
version) + '*>(s));\n'
|
||||
impl += ' }\n'
|
||||
|
||||
impl += ' ' + notreached + '\n'+ \
|
||||
'}\n\n' + \
|
||||
'CefRawPtr<' + clsname + '> ' + typename + '_UnwrapRaw('+ 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 + '_CppToC::UnwrapRaw(s);\n'
|
||||
else:
|
||||
impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapRaw(reinterpret_cast<' + cls.get_capi_name(
|
||||
version) + '*>(s));\n'
|
||||
impl += ' }\n'
|
||||
|
||||
impl += ' ' + notreached + '\n'+ \
|
||||
'}\n\n' + \
|
||||
'CefBaseScoped* ' + typename + '_GetWrapper('+ 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 + '_CppToC::GetWrapper(s);\n'
|
||||
else:
|
||||
impl += ' return ' + clsname + '_' + vstr + '_CppToC::GetWrapper(reinterpret_cast<' + cls.get_capi_name(
|
||||
version) + '*>(s));\n'
|
||||
impl += ' }\n'
|
||||
|
||||
impl += ' ' + notreached + '\n'+ \
|
||||
'}\n'
|
||||
else:
|
||||
impl += structname + '* ' + typename + '_Wrap(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 + '_CppToC::Wrap(c);\n'
|
||||
else:
|
||||
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CppToC::Wrap(c));\n'
|
||||
impl += ' }\n'
|
||||
|
||||
impl += ' ' + notreached + '\n'+ \
|
||||
'}\n\n' + \
|
||||
'CefRefPtr<' + clsname + '> ' + typename + '_Unwrap('+ 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 + '_CppToC::Unwrap(s);\n'
|
||||
else:
|
||||
impl += ' return ' + clsname + '_' + vstr + '_CppToC::Unwrap(reinterpret_cast<' + cls.get_capi_name(
|
||||
version) + '*>(s));\n'
|
||||
impl += ' }\n'
|
||||
|
||||
impl += ' ' + notreached + '\n'+ \
|
||||
'}\n'
|
||||
|
||||
return impl + '\n'
|
||||
|
||||
|
||||
def _version_finder(header, version, name, as_cpp=False):
|
||||
assert version is None or isinstance(version, int), version
|
||||
assert name[-1] != '*', name
|
||||
|
||||
if as_cpp:
|
||||
cls = header.get_class(name)
|
||||
if cls is None:
|
||||
return name
|
||||
return cls.get_name(version=version)
|
||||
|
||||
cls = header.get_capi_class(name)
|
||||
if not cls is None:
|
||||
return cls.get_capi_name(first_version=True)
|
||||
return name
|
||||
|
||||
|
||||
def make_cpptoc_class_impl(header, clsname, impl):
|
||||
# structure names that have already been defined
|
||||
defined_names = header.get_defined_structs()
|
||||
|
||||
# retrieve the class and populate the defined names
|
||||
cls = header.get_class(clsname, defined_names)
|
||||
cls = header.get_class(clsname)
|
||||
if cls is None:
|
||||
raise Exception('Class does not exist: ' + clsname)
|
||||
|
||||
capiname = cls.get_capi_name()
|
||||
prefixname = get_capi_name(clsname[3:], False)
|
||||
|
||||
# retrieve the existing virtual function implementations
|
||||
existing = get_function_impls(impl, 'CEF_CALLBACK')
|
||||
|
||||
base_class_name = header.get_base_class_name(clsname)
|
||||
base_scoped = True if base_class_name == 'CefBaseScoped' else False
|
||||
if base_scoped:
|
||||
@@ -601,80 +813,143 @@ def make_cpptoc_class_impl(header, clsname, impl):
|
||||
else:
|
||||
template_class = 'CefCppToCRefCounted'
|
||||
|
||||
# generate virtual functions
|
||||
virtualimpl = make_cpptoc_virtual_function_impl(
|
||||
header, cls, existing, prefixname, defined_names, base_scoped)
|
||||
if len(virtualimpl) > 0:
|
||||
virtualimpl = '\nnamespace {\n\n// MEMBER FUNCTIONS - Body may be edited by hand.\n\n' + virtualimpl + '} // namespace'
|
||||
|
||||
# the current class is already defined for static functions
|
||||
defined_names.append(cls.get_capi_name())
|
||||
with_versions = cls.is_library_side()
|
||||
versions = list(cls.get_all_versions()) if with_versions else (None,)
|
||||
|
||||
# retrieve the existing static function implementations
|
||||
existing = get_function_impls(impl, 'CEF_EXPORT')
|
||||
existing_static = get_function_impls(impl, 'CEF_EXPORT')
|
||||
|
||||
# generate static functions
|
||||
staticimpl = make_cpptoc_function_impl(cls,
|
||||
cls.get_static_funcs(), existing, None,
|
||||
defined_names, base_scoped)
|
||||
if len(staticimpl) > 0:
|
||||
staticimpl = '\n// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + staticimpl
|
||||
# retrieve the existing virtual function implementations
|
||||
existing_virtual = get_function_impls(impl, 'CEF_CALLBACK')
|
||||
|
||||
resultingimpl = staticimpl + virtualimpl
|
||||
staticout = virtualout = ''
|
||||
customized = False
|
||||
first = True
|
||||
idx = 0
|
||||
|
||||
# any derived classes can be unwrapped
|
||||
unwrapderived = make_cpptoc_unwrap_derived(header, cls, base_scoped)
|
||||
for version in versions:
|
||||
version_finder = functools.partial(_version_finder, header,
|
||||
version) if with_versions else None
|
||||
defined_names.append(cls.get_capi_name(version=version))
|
||||
|
||||
const = '// CONSTRUCTOR - Do not edit by hand.\n\n'+ \
|
||||
clsname+'CppToC::'+clsname+'CppToC() {\n'
|
||||
const += make_cpptoc_virtual_function_assignment(header, cls, prefixname,
|
||||
defined_names)
|
||||
const += '}\n\n'+ \
|
||||
'// DESTRUCTOR - Do not edit by hand.\n\n'+ \
|
||||
clsname+'CppToC::~'+clsname+'CppToC() {\n'
|
||||
if first:
|
||||
first = False
|
||||
|
||||
if not cls.has_attrib('no_debugct_check') and not base_scoped:
|
||||
const += ' shutdown_checker::AssertNotShutdown();\n'
|
||||
# generate static functions
|
||||
staticimpl, scustomized = make_cpptoc_function_impl(
|
||||
cls,
|
||||
cls.get_static_funcs(), existing_static, None, None, defined_names,
|
||||
base_scoped, version, version_finder)
|
||||
if len(staticimpl) > 0:
|
||||
staticout += '// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + staticimpl
|
||||
if scustomized:
|
||||
customized = True
|
||||
|
||||
const += '}\n\n'
|
||||
if len(versions) > 1:
|
||||
staticout += '// HELPER FUNCTIONS - Do not edit by hand.\n\n'
|
||||
staticout += make_cpptoc_version_wrappers(header, cls, base_scoped,
|
||||
versions)
|
||||
|
||||
comment = '' if version is None else (' FOR VERSION %d' % version)
|
||||
|
||||
suffixname = str(version) if (len(versions) > 1 and version > 0) else None
|
||||
|
||||
# generate virtual functions
|
||||
virtualimpl, vcustomized = make_cpptoc_virtual_function_impl(
|
||||
header, cls, existing_virtual, prefixname, suffixname, defined_names,
|
||||
base_scoped, version, version_finder)
|
||||
if len(virtualimpl) > 0:
|
||||
virtualout += 'namespace {\n\n// MEMBER FUNCTIONS' + comment + ' - Body may be edited by hand.\n\n' + \
|
||||
virtualimpl + '} // namespace\n\n'
|
||||
if vcustomized:
|
||||
customized = True
|
||||
|
||||
# any derived classes can be unwrapped
|
||||
unwrapderived = make_cpptoc_unwrap_derived(header, cls, base_scoped,
|
||||
version)
|
||||
|
||||
capiname = cls.get_capi_name(version=version)
|
||||
typename = cls.get_name(version=version) + 'CppToC'
|
||||
|
||||
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\n'
|
||||
|
||||
const += make_cpptoc_virtual_function_assignment(header, cls, prefixname,
|
||||
suffixname, defined_names,
|
||||
version, version_finder)
|
||||
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<> CefOwnPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, '+capiname+'* s) {\n' + \
|
||||
unwrapderived[0] + \
|
||||
' ' + notreached + '\n'+ \
|
||||
'}\n\n' + \
|
||||
'template<> CefRawPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, '+capiname+'* s) {\n' + \
|
||||
unwrapderived[1] + \
|
||||
' ' + notreached + '\n'+ \
|
||||
'}\n\n'
|
||||
else:
|
||||
const += 'template<> CefRefPtr<'+clsname+'> '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+capiname+'* s) {\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 + 'CppToC, ' + clsname + ', ' + capiname + '>'
|
||||
|
||||
if base_scoped:
|
||||
const += 'template<> CefOwnPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, '+capiname+'* s) {\n' + \
|
||||
unwrapderived[0] + \
|
||||
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
|
||||
' return CefOwnPtr<'+clsname+'>();\n'+ \
|
||||
'}\n\n' + \
|
||||
'template<> CefRawPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, '+capiname+'* s) {\n' + \
|
||||
unwrapderived[1] + \
|
||||
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
|
||||
' return nullptr;\n'+ \
|
||||
'}\n\n'
|
||||
if with_versions:
|
||||
pre = post = ''
|
||||
else:
|
||||
const += 'template<> CefRefPtr<'+clsname+'> '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+capiname+'* s) {\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 += '\n\n' + const
|
||||
if len(post) > 0:
|
||||
result += post + '\n'
|
||||
|
||||
return result
|
||||
return (result, customized)
|
||||
|
||||
|
||||
def make_cpptoc_global_impl(header, impl):
|
||||
@@ -684,34 +959,36 @@ def make_cpptoc_global_impl(header, impl):
|
||||
# retrieve the existing global function implementations
|
||||
existing = get_function_impls(impl, 'CEF_EXPORT')
|
||||
|
||||
version_finder = functools.partial(_version_finder, header, None)
|
||||
|
||||
# generate global functions
|
||||
impl = make_cpptoc_function_impl(None,
|
||||
header.get_funcs(), existing, None,
|
||||
defined_names, False)
|
||||
impl, customized = make_cpptoc_function_impl(None,
|
||||
header.get_funcs(), existing,
|
||||
None, None, defined_names, False,
|
||||
None, version_finder)
|
||||
if len(impl) > 0:
|
||||
impl = '\n// GLOBAL FUNCTIONS - 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(versions=True))
|
||||
|
||||
# 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, with_versions=True, other_includes=paths)
|
||||
|
||||
# build the final output
|
||||
result = get_copyright()
|
||||
|
||||
result += includes + '\n' + impl
|
||||
|
||||
return result
|
||||
return (result, customized)
|
||||
|
||||
|
||||
def write_cpptoc_impl(header, clsname, dir):
|
||||
@@ -725,16 +1002,22 @@ def write_cpptoc_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) + '_cpptoc.cc')
|
||||
|
||||
set_notify_context(file)
|
||||
|
||||
if path_exists(file):
|
||||
oldcontents = read_file(file)
|
||||
else:
|
||||
oldcontents = ''
|
||||
|
||||
if clsname is None:
|
||||
newcontents = make_cpptoc_global_impl(header, oldcontents)
|
||||
newcontents, customized = make_cpptoc_global_impl(header, oldcontents)
|
||||
else:
|
||||
newcontents = make_cpptoc_class_impl(header, clsname, oldcontents)
|
||||
return (file, newcontents)
|
||||
newcontents, customized = make_cpptoc_class_impl(header, clsname,
|
||||
oldcontents)
|
||||
|
||||
set_notify_context(None)
|
||||
|
||||
return (file, newcontents, customized)
|
||||
|
||||
|
||||
# test the module
|
||||
|
@@ -6,22 +6,25 @@ from __future__ import absolute_import
|
||||
from cef_parser import *
|
||||
|
||||
|
||||
def make_function_body_block(cls):
|
||||
def make_function_body_block(cls, with_versions):
|
||||
impl = ' // ' + cls.get_name() + ' methods.\n'
|
||||
|
||||
funcs = cls.get_virtual_funcs()
|
||||
for func in funcs:
|
||||
impl += ' ' + func.get_cpp_proto()
|
||||
if cls.is_client_side():
|
||||
impl += ' override;\n'
|
||||
if func.parent.get_name() != cls.get_name():
|
||||
# skip methods that are not directly declared in the current class
|
||||
continue
|
||||
if with_versions:
|
||||
pre = post = ''
|
||||
else:
|
||||
impl += ' override;\n'
|
||||
pre, post = get_version_surround(func)
|
||||
impl += pre + ' ' + func.get_cpp_proto() + ' override;\n' + post
|
||||
|
||||
return impl
|
||||
|
||||
|
||||
def make_function_body(header, cls):
|
||||
impl = make_function_body_block(cls)
|
||||
def make_function_body(header, cls, with_versions):
|
||||
impl = make_function_body_block(cls, with_versions)
|
||||
|
||||
cur_cls = cls
|
||||
while True:
|
||||
@@ -34,7 +37,7 @@ def make_function_body(header, cls):
|
||||
raise Exception('Class does not exist: ' + parent_name)
|
||||
if len(impl) > 0:
|
||||
impl += '\n'
|
||||
impl += make_function_body_block(parent_cls)
|
||||
impl += make_function_body_block(parent_cls, with_versions)
|
||||
cur_cls = header.get_class(parent_name)
|
||||
|
||||
return impl
|
||||
@@ -54,8 +57,6 @@ def make_ctocpp_header(header, clsname):
|
||||
defname += get_capi_name(clsname[3:], False)
|
||||
defname = defname.upper()
|
||||
|
||||
capiname = cls.get_capi_name()
|
||||
|
||||
result = get_copyright()
|
||||
|
||||
result += '#ifndef CEF_LIBCEF_DLL_CTOCPP_'+defname+'_CTOCPP_H_\n'+ \
|
||||
@@ -75,8 +76,10 @@ def make_ctocpp_header(header, clsname):
|
||||
#endif
|
||||
"""
|
||||
|
||||
with_versions = clientside
|
||||
|
||||
# build the function body
|
||||
func_body = make_function_body(header, cls)
|
||||
func_body = make_function_body(header, cls, with_versions)
|
||||
|
||||
# include standard headers
|
||||
if func_body.find('std::map') > 0 or func_body.find('std::multimap') > 0:
|
||||
@@ -86,7 +89,7 @@ def make_ctocpp_header(header, clsname):
|
||||
|
||||
# include the headers for this class
|
||||
result += '\n#include "include/'+cls.get_file_name()+'"'+ \
|
||||
'\n#include "include/capi/'+cls.get_capi_file_name()+'"\n'
|
||||
'\n#include "include/capi/'+cls.get_capi_file_name(versions=with_versions)+'"\n'
|
||||
|
||||
# include headers for any forward declared classes that are not in the same file
|
||||
declares = cls.get_forward_declares()
|
||||
@@ -94,7 +97,7 @@ def make_ctocpp_header(header, clsname):
|
||||
dcls = header.get_class(declare)
|
||||
if dcls.get_file_name() != cls.get_file_name():
|
||||
result += '#include "include/'+dcls.get_file_name()+'"\n' \
|
||||
'#include "include/capi/'+dcls.get_capi_file_name()+'"\n'
|
||||
'#include "include/capi/'+dcls.get_capi_file_name(versions=with_versions)+'"\n'
|
||||
|
||||
base_class_name = header.get_base_class_name(clsname)
|
||||
base_scoped = True if base_class_name == 'CefBaseScoped' else False
|
||||
@@ -106,21 +109,66 @@ def make_ctocpp_header(header, clsname):
|
||||
template_class = 'CefCToCppRefCounted'
|
||||
|
||||
result += '#include "libcef_dll/ctocpp/' + template_file + '"'
|
||||
result += '\n\n// Wrap a C structure with a C++ class.\n'
|
||||
|
||||
if clientside:
|
||||
result += '// This class may be instantiated and accessed DLL-side only.\n'
|
||||
if with_versions:
|
||||
pre = post = ''
|
||||
else:
|
||||
result += '// This class may be instantiated and accessed wrapper-side only.\n'
|
||||
pre, post = get_version_surround(cls, long=True)
|
||||
if len(pre) > 0:
|
||||
result += '\n\n' + pre.strip()
|
||||
|
||||
result += 'class '+clsname+'CToCpp\n'+ \
|
||||
' : public ' + template_class + '<'+clsname+'CToCpp, '+clsname+', '+capiname+'> {\n'+ \
|
||||
' public:\n'+ \
|
||||
' '+clsname+'CToCpp();\n'+ \
|
||||
' virtual ~'+clsname+'CToCpp();\n\n'
|
||||
result += '\n\n'
|
||||
|
||||
result += func_body
|
||||
result += '};\n\n'
|
||||
versions = cls.get_all_versions() if with_versions else (None,)
|
||||
|
||||
for version in versions:
|
||||
result += '// Wrap a C structure with a C++ class%s.\n' % \
|
||||
('' if version is None else ' at API version %d' % version)
|
||||
if clientside:
|
||||
result += '// This class may be instantiated and accessed DLL-side only.\n'
|
||||
else:
|
||||
result += '// This class may be instantiated and accessed wrapper-side only.\n'
|
||||
|
||||
capiname = cls.get_capi_name(version=version)
|
||||
if version is None:
|
||||
typename = clsname + 'CToCpp'
|
||||
else:
|
||||
typename = clsname + '_%d_CToCpp' % version
|
||||
|
||||
result += 'class '+typename+'\n'+ \
|
||||
' : public ' + template_class + '<'+typename+', '+clsname+', '+capiname+'> {\n'+ \
|
||||
' public:\n'+ \
|
||||
' '+typename+'();\n'+ \
|
||||
' virtual ~'+typename+'();\n\n'
|
||||
|
||||
result += func_body
|
||||
result += '};\n\n'
|
||||
|
||||
typename = clsname + 'CToCpp'
|
||||
if len(versions) > 1:
|
||||
result += '// Helpers to return objects at the globally configured API version.\n'
|
||||
structname = cls.get_capi_name(version=versions[0])
|
||||
if base_scoped:
|
||||
result += 'CefOwnPtr<' + clsname + '> ' + typename + '_Wrap(' + structname + '* s);\n' + \
|
||||
structname + '* ' + typename + '_UnwrapOwn(CefOwnPtr<' + clsname + '> c);\n' + \
|
||||
structname + '* ' + typename + '_UnwrapRaw(CefRawPtr<' + clsname + '> c);\n\n'
|
||||
else:
|
||||
result += 'CefRefPtr<' + clsname + '> ' + typename + '_Wrap(' + structname + '* s);\n' + \
|
||||
structname + '* ' + typename + '_Unwrap(CefRefPtr<' + clsname + '> c);\n\n'
|
||||
else:
|
||||
if versions[0] is None:
|
||||
targetname = clsname + 'CToCpp'
|
||||
else:
|
||||
targetname = clsname + '_%d_CToCpp' % versions[0]
|
||||
if base_scoped:
|
||||
result += 'constexpr auto ' + typename + '_Wrap = ' + targetname + '::Wrap;\n' + \
|
||||
'constexpr auto ' + typename + '_UnwrapOwn = ' + targetname + '::UnwrapOwn;\n' + \
|
||||
'constexpr auto ' + typename + '_UnwrapRaw = ' + targetname + '::UnwrapRaw;\n\n'
|
||||
else:
|
||||
result += 'constexpr auto ' + typename + '_Wrap = ' + targetname + '::Wrap;\n' + \
|
||||
'constexpr auto ' + typename + '_Unwrap = ' + targetname + '::Unwrap;\n\n'
|
||||
if len(post) > 0:
|
||||
result += post + '\n'
|
||||
|
||||
result += '#endif // CEF_LIBCEF_DLL_CTOCPP_' + defname + '_CTOCPP_H_'
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -6,6 +6,7 @@ from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
from bazel_util import bazel_substitute, bazel_last_error, bazel_set_quiet
|
||||
from cef_version import VersionFormatter
|
||||
from clang_util import clang_format_inplace
|
||||
from date_util import *
|
||||
from exec_util import exec_cmd
|
||||
from file_util import *
|
||||
@@ -226,7 +227,12 @@ def transfer_doxyfile(dst_dir, quiet):
|
||||
sys.stdout.write('Creating Doxyfile file.\n')
|
||||
|
||||
|
||||
def transfer_gypi_files(src_dir, gypi_paths, gypi_path_prefix, dst_dir, quiet):
|
||||
def transfer_gypi_files(src_dir,
|
||||
gypi_paths,
|
||||
gypi_path_prefix,
|
||||
dst_dir,
|
||||
quiet,
|
||||
format=False):
|
||||
""" Transfer files from one location to another. """
|
||||
for path in gypi_paths:
|
||||
src = os.path.join(src_dir, path)
|
||||
@@ -235,6 +241,11 @@ def transfer_gypi_files(src_dir, gypi_paths, gypi_path_prefix, dst_dir, quiet):
|
||||
make_dir(dst_path, quiet)
|
||||
copy_file(src, dst, quiet)
|
||||
|
||||
# Apply clang-format for C/C++ files.
|
||||
if format and os.path.splitext(dst)[1][1:] in ('c', 'cc', 'cpp', 'h'):
|
||||
print(dst)
|
||||
clang_format_inplace(dst)
|
||||
|
||||
|
||||
def extract_toolchain_cmd(build_dir,
|
||||
exe_name,
|
||||
@@ -925,17 +936,19 @@ if mode == 'standard' or mode == 'minimal':
|
||||
transfer_gypi_files(cef_dir, cef_paths2['includes_wrapper'], \
|
||||
'include/', include_dir, options.quiet)
|
||||
transfer_gypi_files(cef_dir, cef_paths['autogen_cpp_includes'], \
|
||||
'include/', include_dir, options.quiet)
|
||||
'include/', include_dir, options.quiet, format=True)
|
||||
transfer_gypi_files(cef_dir, cef_paths['autogen_capi_includes'], \
|
||||
'include/', include_dir, options.quiet)
|
||||
'include/', include_dir, options.quiet, format=True)
|
||||
|
||||
# Transfer generated include files.
|
||||
generated_includes = [
|
||||
'cef_api_versions.h',
|
||||
'cef_color_ids.h',
|
||||
'cef_command_ids.h',
|
||||
'cef_config.h',
|
||||
'cef_pack_resources.h',
|
||||
'cef_pack_strings.h',
|
||||
'cef_version.h',
|
||||
]
|
||||
for include in generated_includes:
|
||||
# Debug and Release build should be the same so grab whichever exists.
|
||||
@@ -953,7 +966,7 @@ if mode == 'standard' or mode == 'minimal':
|
||||
transfer_gypi_files(cef_dir, cef_paths2['libcef_dll_wrapper_sources_common'], \
|
||||
'libcef_dll/', libcef_dll_dir, options.quiet)
|
||||
transfer_gypi_files(cef_dir, cef_paths['autogen_client_side'], \
|
||||
'libcef_dll/', libcef_dll_dir, options.quiet)
|
||||
'libcef_dll/', libcef_dll_dir, options.quiet, format=True)
|
||||
|
||||
if mode == 'standard' or mode == 'minimal':
|
||||
# transfer additional files
|
||||
|
@@ -37,6 +37,13 @@ def make_gypi_file(header):
|
||||
result += " 'include/capi/" + get_capi_file_name(filename) + "',\n"
|
||||
result += " ],\n"
|
||||
|
||||
# capi version includes
|
||||
result += " 'autogen_capi_versions_includes': [\n"
|
||||
for filename in filenames:
|
||||
result += " 'include/capi/" + get_capi_file_name(
|
||||
filename, versions=True) + "',\n"
|
||||
result += " ],\n"
|
||||
|
||||
classes = sorted(header.get_class_names())
|
||||
|
||||
# library side includes
|
||||
|
@@ -10,7 +10,8 @@ import os
|
||||
# Other headers that export C API functions.
|
||||
OTHER_HEADERS = [
|
||||
'cef_api_hash.h',
|
||||
'cef_version.h',
|
||||
'cef_id_mappers.h',
|
||||
'cef_version_info.h',
|
||||
'internal/cef_dump_without_crashing_internal.h',
|
||||
'internal/cef_logging_internal.h',
|
||||
'internal/cef_string_list.h',
|
||||
@@ -37,12 +38,11 @@ def make_libcef_dll_dylib_impl_parts(name, retval, args):
|
||||
|
||||
declare = 'decltype(&%s) %s;\n' % (name, name)
|
||||
|
||||
init = ' INIT_ENTRY(%s);' % name
|
||||
init = 'INIT_ENTRY(%s);\n' % name
|
||||
|
||||
impl = """NO_SANITIZE("cfi-icall") %s %s(%s) {
|
||||
%sg_libcef_pointers.%s(%s);
|
||||
}
|
||||
|
||||
""" % (retval, name, ', '.join(args), 'return '
|
||||
if retval != 'void' else '', name, arg_names)
|
||||
|
||||
@@ -70,9 +70,10 @@ def make_libcef_dll_dylib_impl(header):
|
||||
# Include required headers for global functions.
|
||||
for func in header.get_funcs():
|
||||
declare, init, impl = make_libcef_dll_dylib_impl_func(func)
|
||||
ptr_declare += declare
|
||||
ptr_init += init
|
||||
ptr_impl += impl
|
||||
pre, post = get_version_surround(func)
|
||||
ptr_declare += pre + declare + post
|
||||
ptr_init += pre + init + post
|
||||
ptr_impl += pre + impl + post + '\n'
|
||||
|
||||
filename = func.get_file_name()
|
||||
if not filename in filenames:
|
||||
@@ -85,9 +86,13 @@ def make_libcef_dll_dylib_impl(header):
|
||||
funcs = cls.get_static_funcs()
|
||||
for func in funcs:
|
||||
declare, init, impl = make_libcef_dll_dylib_impl_func(func)
|
||||
ptr_declare += declare
|
||||
ptr_init += init
|
||||
ptr_impl += impl
|
||||
pre1, post1 = get_version_surround(func)
|
||||
pre2, post2 = get_version_surround(cls)
|
||||
pre = pre1 + pre2
|
||||
post = post1 + post2
|
||||
ptr_declare += pre + declare + post
|
||||
ptr_init += pre + init + post
|
||||
ptr_impl += pre + impl + post + '\n'
|
||||
|
||||
if len(funcs) > 0:
|
||||
filename = cls.get_file_name()
|
||||
@@ -106,7 +111,7 @@ def make_libcef_dll_dylib_impl(header):
|
||||
func['name'], func['retval'], func['args'])
|
||||
ptr_declare += declare
|
||||
ptr_init += init
|
||||
ptr_impl += impl
|
||||
ptr_impl += impl + '\n'
|
||||
|
||||
includes.append('#include "include/%s"' % other)
|
||||
|
||||
@@ -202,7 +207,9 @@ if __name__ == "__main__":
|
||||
# Create the header object. Should match the logic in translator.py.
|
||||
header = obj_header()
|
||||
header.set_root_directory(cpp_header_dir)
|
||||
excluded_files = ['cef_api_hash.h', 'cef_application_mac.h', 'cef_version.h']
|
||||
excluded_files = [
|
||||
'cef_api_hash.h', 'cef_application_mac.h', 'cef_version_info.h'
|
||||
]
|
||||
header.add_directory(cpp_header_dir, excluded_files)
|
||||
header.add_directory(os.path.join(cpp_header_dir, 'test'))
|
||||
header.add_directory(os.path.join(cpp_header_dir, 'views'))
|
||||
|
@@ -16,7 +16,7 @@ import string
|
||||
import sys
|
||||
|
||||
|
||||
def MakeFileSegment(input, all_names):
|
||||
def _make_pack_header_segment(input, ids):
|
||||
result = """
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -26,8 +26,93 @@ def MakeFileSegment(input, all_names):
|
||||
filename = os.path.split(input)[1]
|
||||
result = result.replace('$FILE$', filename)
|
||||
|
||||
for name, id in ids.items():
|
||||
result += "\n#define %s %s" % (name, id)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def make_pack_header(output, all_files):
|
||||
# header string
|
||||
result = get_copyright(full=True, translator=False) + \
|
||||
"""//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file is generated by the make_pack_header.py tool.
|
||||
//
|
||||
|
||||
#ifndef $GUARD$
|
||||
#define $GUARD$
|
||||
#pragma once"""
|
||||
|
||||
# generate the file segments
|
||||
for file, ids in all_files.items():
|
||||
result += _make_pack_header_segment(file, ids)
|
||||
|
||||
# footer string
|
||||
result += \
|
||||
"""
|
||||
|
||||
#endif // $GUARD$
|
||||
"""
|
||||
|
||||
# add the guard string
|
||||
filename = os.path.split(output)[1]
|
||||
guard = 'CEF_INCLUDE_' + filename.replace('.', '_').upper() + '_'
|
||||
result = result.replace('$GUARD$', guard)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _get_cpp_var_name(output):
|
||||
filename_no_ext = os.path.splitext(os.path.split(output)[1])[0]
|
||||
|
||||
# Convert to CamelCase after removing the 'cef_' prefix.
|
||||
parts = filename_no_ext.split('_')[1:]
|
||||
return "".join([p[0].upper() + p[1:] for p in parts])
|
||||
|
||||
|
||||
def make_pack_inc(output, all_files):
|
||||
var = 'IdNames' + _get_cpp_var_name(output)
|
||||
|
||||
result = get_copyright(full=False, translator=False) + \
|
||||
"""//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file was generated by the make_pack_header.py tool.
|
||||
//
|
||||
|
||||
namespace {
|
||||
|
||||
struct $var$ {
|
||||
int id;
|
||||
const char* const name;
|
||||
};
|
||||
|
||||
const $var$ k$var$[] = {""".replace('$var$', var)
|
||||
|
||||
for file, ids in all_files.items():
|
||||
result += '\n // From %s:' % file
|
||||
for name, id in ids.items():
|
||||
result += '\n {%s, "%s"},' % (id, name)
|
||||
|
||||
result += \
|
||||
"""
|
||||
};
|
||||
|
||||
const size_t k$var$Size = std::size(k$var$);
|
||||
|
||||
} // namespace
|
||||
""".replace('$var$', var)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _get_defines(input, all_names):
|
||||
contents = read_file(input)
|
||||
|
||||
ids = {}
|
||||
|
||||
# Format for Windows builds with resource whitelisting enabled [1]:
|
||||
# #define IDR_RESOURCE_NAME (::ui::WhitelistedResource<12345>(), 12345)
|
||||
# Format for other builds:
|
||||
@@ -50,54 +135,48 @@ def MakeFileSegment(input, all_names):
|
||||
else:
|
||||
all_names[name] = 1
|
||||
|
||||
result += "\n#define %s %s" % (name, id)
|
||||
ids[name] = id
|
||||
|
||||
return result
|
||||
return ids
|
||||
|
||||
|
||||
def MakeFile(output, input):
|
||||
# header string
|
||||
result = get_copyright(full=True, translator=False) + \
|
||||
"""//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// This file is generated by the make_pack_header.py tool.
|
||||
//
|
||||
|
||||
#ifndef $GUARD$
|
||||
#define $GUARD$
|
||||
#pragma once"""
|
||||
|
||||
def write_pack_header(out_header_file, out_inc_file, inputs):
|
||||
# sort the input files by name
|
||||
input = sorted(input, key=lambda path: os.path.split(path)[1])
|
||||
inputs = sorted(inputs, key=lambda path: os.path.split(path)[1])
|
||||
|
||||
all_names = {}
|
||||
all_files = {}
|
||||
|
||||
# generate the file segments
|
||||
for file in input:
|
||||
result += MakeFileSegment(file, all_names)
|
||||
for file in inputs:
|
||||
filename = os.path.split(file)[1]
|
||||
assert not filename in all_files, filename
|
||||
all_files[filename] = _get_defines(file, all_names)
|
||||
|
||||
# footer string
|
||||
result += \
|
||||
"""
|
||||
out_file = os.path.abspath(out_header_file)
|
||||
result = make_pack_header(out_file, all_files)
|
||||
if not bool(result):
|
||||
sys.stderr.write('Failed to create %s\n' % out_file)
|
||||
sys.exit(1)
|
||||
retval1 = write_file_if_changed(out_file, result)
|
||||
|
||||
#endif // $GUARD$
|
||||
"""
|
||||
out_file = os.path.abspath(out_inc_file)
|
||||
result = make_pack_inc(out_file, all_files)
|
||||
if not bool(result):
|
||||
sys.stderr.write('Failed to create %s\n' % out_file)
|
||||
sys.exit(1)
|
||||
retval2 = write_file_if_changed(out_file, result)
|
||||
|
||||
# add the guard string
|
||||
filename = os.path.split(output)[1]
|
||||
guard = 'CEF_INCLUDE_' + filename.replace('.', '_').upper() + '_'
|
||||
result = result.replace('$GUARD$', guard)
|
||||
|
||||
write_file_if_changed(output, result)
|
||||
return retval1 #or retval2
|
||||
|
||||
|
||||
def main(argv):
|
||||
if len(argv) < 3:
|
||||
print(("Usage:\n %s <output_filename> <input_file1> [input_file2] ... " %
|
||||
argv[0]))
|
||||
if len(argv) < 4:
|
||||
print(
|
||||
"Usage:\n %s <output_header_file> <output_inc_file> <input_file1> [input_file2] ... "
|
||||
% argv[0])
|
||||
sys.exit(-1)
|
||||
MakeFile(argv[1], argv[2:])
|
||||
write_pack_header(argv[1], argv[2], argv[3:])
|
||||
|
||||
|
||||
if '__main__' == __name__:
|
||||
|
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
python3.bat tools\make_version_header.py include\cef_version.h
|
@@ -12,9 +12,6 @@ import sys
|
||||
|
||||
|
||||
def make_version_header(header):
|
||||
if not git.is_checkout('.'):
|
||||
raise Exception('Not a valid checkout')
|
||||
|
||||
result = get_copyright(full=True, translator=False) + \
|
||||
"""//
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -41,33 +38,6 @@ def make_version_header(header):
|
||||
#define DO_MAKE_STRING(p) #p
|
||||
#define MAKE_STRING(p) DO_MAKE_STRING(p)
|
||||
|
||||
#ifndef APSTUDIO_HIDDEN_SYMBOLS
|
||||
|
||||
#include "include/internal/cef_export.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Returns CEF version information for the libcef library. The |entry|
|
||||
// parameter describes which version component will be returned:
|
||||
// 0 - CEF_VERSION_MAJOR
|
||||
// 1 - CEF_VERSION_MINOR
|
||||
// 2 - CEF_VERSION_PATCH
|
||||
// 3 - CEF_COMMIT_NUMBER
|
||||
// 4 - CHROME_VERSION_MAJOR
|
||||
// 5 - CHROME_VERSION_MINOR
|
||||
// 6 - CHROME_VERSION_BUILD
|
||||
// 7 - CHROME_VERSION_PATCH
|
||||
///
|
||||
CEF_EXPORT int cef_version_info(int entry);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // APSTUDIO_HIDDEN_SYMBOLS
|
||||
|
||||
#endif // CEF_INCLUDE_CEF_VERSION_H_
|
||||
"""
|
||||
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
python3 tools/make_version_header.py include/cef_version.h
|
@@ -43,7 +43,9 @@ if __name__ == "__main__":
|
||||
|
||||
# create the header object
|
||||
header = obj_header()
|
||||
excluded_files = ['cef_api_hash.h', 'cef_application_mac.h', 'cef_version.h']
|
||||
excluded_files = [
|
||||
'cef_api_hash.h', 'cef_application_mac.h', 'cef_version_info.h'
|
||||
]
|
||||
header.add_directory(sys.argv[1], excluded_files)
|
||||
|
||||
# dump the result to stdout
|
||||
|
@@ -285,10 +285,6 @@ follows.
|
||||
|
||||
void CefClassCToCpp::Function(cpp_params)
|
||||
{
|
||||
// Structure Verification
|
||||
if (CEF_MEMBER_MISSING(struct_, function))
|
||||
return;
|
||||
|
||||
// Parameter Verification (Optional)
|
||||
// Verify the C++ parameter values.
|
||||
// ...
|
||||
@@ -309,10 +305,6 @@ follows.
|
||||
|
||||
cpp_retval CefClassCToCpp::Function(cpp_params)
|
||||
{
|
||||
// Structure Verification
|
||||
if (CEF_MEMBER_MISSING(struct_, function))
|
||||
return default_retval; // Configured or defaulted automatically.
|
||||
|
||||
// Parameter Verification (Optional)
|
||||
// Verify the C++ parameter values.
|
||||
// ...
|
||||
|
@@ -3,111 +3,66 @@
|
||||
# can be found in the LICENSE file.
|
||||
|
||||
from __future__ import absolute_import
|
||||
import sys
|
||||
from cef_parser import *
|
||||
from cef_parser import obj_header
|
||||
from cef_version import VersionFormatter
|
||||
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_wrapper_types_header import *
|
||||
from make_capi_header import write_capi_header
|
||||
from make_capi_versions_header import write_capi_versions_header
|
||||
from make_cpptoc_header import write_cpptoc_header
|
||||
from make_cpptoc_impl import write_cpptoc_impl
|
||||
from make_ctocpp_header import write_ctocpp_header
|
||||
from make_ctocpp_impl import write_ctocpp_impl
|
||||
from make_gypi_file import write_gypi_file
|
||||
from make_libcef_dll_dylib_impl import write_libcef_dll_dylib_impl
|
||||
from make_wrapper_types_header import write_wrapper_types_header
|
||||
from optparse import OptionParser
|
||||
import sys
|
||||
|
||||
# cannot be loaded as a module
|
||||
if __name__ != "__main__":
|
||||
sys.stderr.write('This file cannot be loaded as a module!')
|
||||
sys.exit()
|
||||
FILE_HEADER = """#
|
||||
# This file was generated by the CEF translator tool and should not edited
|
||||
# by hand.
|
||||
#
|
||||
# $hash=$$HASH$$$
|
||||
#
|
||||
|
||||
# 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')
|
||||
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 _write_version():
|
||||
return FILE_HEADER + VersionFormatter().get_version_string()
|
||||
|
||||
|
||||
def update_file(file, newcontents):
|
||||
def _write_gitignore(gitignore, gitignore_file, root_dir):
|
||||
contents = FILE_HEADER
|
||||
|
||||
in_file = gitignore_file + '.in'
|
||||
if os.path.isfile(in_file):
|
||||
contents += read_file(in_file)
|
||||
|
||||
# Include ourselves in generated files.
|
||||
gitignore.append(gitignore_file)
|
||||
|
||||
root_dir_len = len(root_dir)
|
||||
contents += '\n'.join(
|
||||
[p[root_dir_len:].replace('\\', '/') for p in sorted(gitignore)])
|
||||
|
||||
return contents
|
||||
|
||||
|
||||
def _update_file(file, newcontents, customized, force, clean, backup,
|
||||
gitignore):
|
||||
""" Replaces the contents of |file| with |newcontents| if necessary. """
|
||||
if clean:
|
||||
if not customized:
|
||||
return 1 if remove_file(file, quiet=False) else 0
|
||||
print('File %s has customizations and will not be removed' % file)
|
||||
return 0
|
||||
|
||||
if not customized and not gitignore is None:
|
||||
gitignore.append(file)
|
||||
|
||||
oldcontents = ''
|
||||
oldhash = ''
|
||||
|
||||
@@ -122,7 +77,7 @@ def update_file(file, newcontents):
|
||||
hash_end = "$"
|
||||
hash_token = "$$HASH$$"
|
||||
|
||||
if not options.force and path_exists(file):
|
||||
if not force and path_exists(file):
|
||||
oldcontents = read_file(file)
|
||||
|
||||
# Extract the existing hash.
|
||||
@@ -137,106 +92,264 @@ def update_file(file, newcontents):
|
||||
|
||||
if oldhash == newhash:
|
||||
# Pre-formatted contents have not changed.
|
||||
return
|
||||
return 0
|
||||
|
||||
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'):
|
||||
# Apply clang-format for C/C++ files. This is slow, so we only do it for
|
||||
# customized files.
|
||||
if customized and 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")
|
||||
raise Exception("Call to clang-format failed for %s" % file)
|
||||
|
||||
if options.backup and oldcontents != '':
|
||||
if backup and oldcontents != '':
|
||||
backup_file(file)
|
||||
|
||||
filedir = os.path.split(file)[0]
|
||||
if not os.path.isdir(filedir):
|
||||
make_dir(filedir)
|
||||
|
||||
print('Writing file %s' % file)
|
||||
write_file(file, newcontents)
|
||||
|
||||
global writect
|
||||
writect += 1
|
||||
return 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))
|
||||
def translate(cef_dir,
|
||||
force=False,
|
||||
clean=False,
|
||||
backup=False,
|
||||
verbose=False,
|
||||
selected_classes=None):
|
||||
# determine the paths
|
||||
root_dir = os.path.abspath(cef_dir)
|
||||
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')
|
||||
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')
|
||||
libcef_dll_dylib_impl = os.path.join(libcef_dll_dir, 'wrapper',
|
||||
'libcef_dll_dylib.cc')
|
||||
version_file = os.path.join(root_dir, 'VERSION.stamp')
|
||||
gitignore_file = os.path.join(root_dir, '.gitignore')
|
||||
|
||||
# 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))
|
||||
# make sure the header directory exists
|
||||
if not path_exists(cpp_header_dir):
|
||||
sys.stderr.write('ERROR: Directory ' + cpp_header_dir +
|
||||
' does not exist.\n')
|
||||
sys.exit(1)
|
||||
|
||||
# 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
|
||||
# create the header object
|
||||
if verbose:
|
||||
print('Parsing C++ headers from ' + cpp_header_dir + '...')
|
||||
header = obj_header()
|
||||
|
||||
classes = sorted(classes)
|
||||
# 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_info.h'
|
||||
]
|
||||
header.add_directory(cpp_header_dir, excluded_files)
|
||||
header.add_directory(cpp_header_test_dir)
|
||||
header.add_directory(cpp_header_views_dir)
|
||||
|
||||
# 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))
|
||||
# Track the number of files that were written.
|
||||
writect = 0
|
||||
|
||||
# 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))
|
||||
# Track files that are not customized.
|
||||
gitignore = []
|
||||
|
||||
# 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))
|
||||
debug_string = ''
|
||||
|
||||
# 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))
|
||||
try:
|
||||
|
||||
# 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 C API header
|
||||
if verbose:
|
||||
print('In C API header directory ' + capi_header_dir + '...')
|
||||
filenames = sorted(header.get_file_names())
|
||||
for filename in filenames:
|
||||
if verbose:
|
||||
print('Generating ' + filename + ' C API headers...')
|
||||
debug_string = 'CAPI header for ' + filename
|
||||
writect += _update_file(*write_capi_header(header, capi_header_dir,
|
||||
filename), False, force, clean,
|
||||
backup, gitignore)
|
||||
debug_string = 'CAPI versions header for ' + filename
|
||||
writect += _update_file(*write_capi_versions_header(
|
||||
header, capi_header_dir, filename), False, force, clean, backup,
|
||||
gitignore)
|
||||
|
||||
# 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 wrapper types header
|
||||
if verbose:
|
||||
print('Generating wrapper types header...')
|
||||
debug_string = 'wrapper types header'
|
||||
writect += _update_file(*write_wrapper_types_header(
|
||||
header, wrapper_types_header), False, force, clean, backup, gitignore)
|
||||
|
||||
# Update the API hash header file if necessary. 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')
|
||||
if write_api_hash_header(api_hash_header, cpp_header_dir):
|
||||
writect += 1
|
||||
# build the list of classes to parse
|
||||
allclasses = header.get_class_names()
|
||||
if not selected_classes is None:
|
||||
for cls in selected_classes:
|
||||
if not cls in allclasses:
|
||||
sys.stderr.write('ERROR: Unknown class: %s\n' % cls)
|
||||
sys.exit(1)
|
||||
classes = selected_classes
|
||||
else:
|
||||
classes = allclasses
|
||||
|
||||
if not options.quiet:
|
||||
sys.stdout.write('Done - Wrote ' + str(writect) + ' files.\n')
|
||||
classes = sorted(classes)
|
||||
|
||||
# output CppToC global file
|
||||
if verbose:
|
||||
print('Generating CppToC global implementation...')
|
||||
debug_string = 'CppToC global implementation'
|
||||
writect += _update_file(*write_cpptoc_impl(
|
||||
header, None, cpptoc_global_impl), force, clean, backup, gitignore)
|
||||
|
||||
# output CToCpp global file
|
||||
if verbose:
|
||||
print('Generating CToCpp global implementation...')
|
||||
debug_string = 'CToCpp global implementation'
|
||||
writect += _update_file(*write_ctocpp_impl(
|
||||
header, None, ctocpp_global_impl), force, clean, backup, gitignore)
|
||||
|
||||
# output CppToC class files
|
||||
if verbose:
|
||||
print('In CppToC directory ' + cpptoc_dir + '...')
|
||||
for cls in classes:
|
||||
if verbose:
|
||||
print('Generating ' + cls + 'CppToC class header...')
|
||||
debug_string = 'CppToC class header for ' + cls
|
||||
writect += _update_file(*write_cpptoc_header(header, cls, cpptoc_dir),
|
||||
False, force, clean, backup, gitignore)
|
||||
|
||||
if verbose:
|
||||
print('Generating ' + cls + 'CppToC class implementation...')
|
||||
debug_string = 'CppToC class implementation for ' + cls
|
||||
writect += _update_file(*write_cpptoc_impl(header, cls, cpptoc_dir),
|
||||
force, clean, backup, gitignore)
|
||||
|
||||
# output CppToC class files
|
||||
if verbose:
|
||||
print('In CToCpp directory ' + ctocpp_dir + '...')
|
||||
for cls in classes:
|
||||
if verbose:
|
||||
print('Generating ' + cls + 'CToCpp class header...')
|
||||
debug_string = 'CToCpp class header for ' + cls
|
||||
writect += _update_file(*write_ctocpp_header(header, cls, ctocpp_dir),
|
||||
False, force, clean, backup, gitignore)
|
||||
if verbose:
|
||||
print('Generating ' + cls + 'CToCpp class implementation...')
|
||||
debug_string = 'CToCpp class implementation for ' + cls
|
||||
writect += _update_file(*write_ctocpp_impl(header, cls, ctocpp_dir),
|
||||
force, clean, backup, gitignore)
|
||||
|
||||
# output the gypi file
|
||||
if verbose:
|
||||
print('Generating ' + gypi_file + ' file...')
|
||||
debug_string = gypi_file
|
||||
writect += _update_file(*write_gypi_file(header, gypi_file), False, force,
|
||||
clean, backup, gitignore)
|
||||
|
||||
# output the libcef dll dylib file
|
||||
if verbose:
|
||||
print('Generating ' + libcef_dll_dylib_impl + ' file...')
|
||||
debug_string = libcef_dll_dylib_impl
|
||||
writect += _update_file(*write_libcef_dll_dylib_impl(
|
||||
header, libcef_dll_dylib_impl), False, force, clean, backup, gitignore)
|
||||
|
||||
# output the VERSION.stamp file that triggers cef_version.h regen at build time
|
||||
if verbose:
|
||||
print('Generating ' + version_file + ' file...')
|
||||
debug_string = version_file
|
||||
writect += _update_file(version_file,
|
||||
_write_version(), False, force, clean, backup,
|
||||
gitignore)
|
||||
|
||||
# output the top-level .gitignore file that lists uncustomized files
|
||||
if verbose:
|
||||
print('Generating ' + gitignore_file + ' file...')
|
||||
debug_string = gitignore_file
|
||||
writect += _update_file(gitignore_file,
|
||||
_write_gitignore(gitignore, gitignore_file,
|
||||
root_dir), False, force, clean,
|
||||
backup, None)
|
||||
|
||||
except (AssertionError, Exception) as e:
|
||||
sys.stderr.write('ERROR: while processing %s\n' % debug_string)
|
||||
raise
|
||||
|
||||
if verbose or writect > 0:
|
||||
print('Done translating - %s %d files.' % ('Removed'
|
||||
if clean else 'Wrote', writect))
|
||||
|
||||
return writect
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from optparse import OptionParser
|
||||
|
||||
# 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(
|
||||
'--clean',
|
||||
action='store_true',
|
||||
dest='clean',
|
||||
default=False,
|
||||
help='clean all files without custom modifications')
|
||||
parser.add_option(
|
||||
'-c',
|
||||
'--classes',
|
||||
dest='classes',
|
||||
action='append',
|
||||
help='only translate the specified classes')
|
||||
parser.add_option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
dest='verbose',
|
||||
default=False,
|
||||
help='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()
|
||||
|
||||
if translate(options.rootdir, options.force, options.clean, options.backup,
|
||||
options.verbose, options.classes) == 0:
|
||||
if not options.verbose:
|
||||
print('Nothing to do.')
|
||||
elif not options.clean:
|
||||
print('WARNING: You must run version_manager.py to update API hashes.')
|
||||
|
549
tools/version_manager.py
Normal file
549
tools/version_manager.py
Normal file
@@ -0,0 +1,549 @@
|
||||
# Copyright (c) 2024 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
|
||||
from __future__ import print_function
|
||||
from cef_api_hash import cef_api_hash
|
||||
from cef_version import VersionFormatter
|
||||
from date_util import get_date
|
||||
from file_util import read_file, read_json_file, write_file, write_json_file
|
||||
from git_util import exec_git_cmd
|
||||
import os
|
||||
import sys
|
||||
from translator import translate
|
||||
from version_util import *
|
||||
|
||||
|
||||
def get_next_api_revision(api_versions_file, major_version):
|
||||
""" Returns the next available API revision for |major_version|.
|
||||
"""
|
||||
json = read_json_file(api_versions_file)
|
||||
if not bool(json):
|
||||
return 0
|
||||
|
||||
assert 'last' in json, api_versions_file
|
||||
last_version, last_revision = version_parse(json['last'])
|
||||
|
||||
if major_version < last_version:
|
||||
sys.stderr.write(
|
||||
'ERROR: Cannot add new API versions on old branches/checkouts '
|
||||
'(found %d, expected >= %d)\b' % (major_version, last_version))
|
||||
return -1
|
||||
|
||||
if major_version == last_version:
|
||||
# Increment the revision for the current major version.
|
||||
new_revision = last_revision + 1
|
||||
assert new_revision <= 99, new_revision
|
||||
return new_revision
|
||||
|
||||
# Reset the revision for a new major version.
|
||||
return 0
|
||||
|
||||
|
||||
_CALC = None
|
||||
|
||||
|
||||
def compute_api_hashes(cpp_header_dir, api_version, next_allowed, debug_dir,
|
||||
verbose):
|
||||
""" Computes API hashes for the specified |api_version|.
|
||||
"""
|
||||
if not debug_dir is None:
|
||||
debug_dir = os.path.join(debug_dir, api_version)
|
||||
|
||||
if not next_allowed:
|
||||
# Next usage is banned with explicit API versions.
|
||||
assert not api_version in UNTRACKED_VERSIONS, api_version
|
||||
added_defines = [
|
||||
# Using CEF_API_VERSION_NEXT is an error.
|
||||
'CEF_API_VERSION_NEXT="Please_specify_an_exact_CEF_version"',
|
||||
]
|
||||
else:
|
||||
added_defines = None
|
||||
|
||||
global _CALC
|
||||
if _CALC is None:
|
||||
_CALC = cef_api_hash(cpp_header_dir, verbose=verbose)
|
||||
|
||||
hashes = _CALC.calculate(api_version, debug_dir, added_defines)
|
||||
if bool(hashes):
|
||||
if api_version in UNTRACKED_VERSIONS:
|
||||
label = version_label(api_version)
|
||||
label = label[0:1].upper() + label[1:]
|
||||
hashes['comment'] = '%s last updated %s.' % (label, get_date())
|
||||
else:
|
||||
hashes['comment'] = 'Added %s.' % get_date()
|
||||
return hashes
|
||||
|
||||
|
||||
def same_api_hashes(hashes1, hashes2):
|
||||
for key in ('universal', 'linux', 'mac', 'windows'):
|
||||
if hashes1[key] != hashes2[key]:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def compute_next_api_verson(api_versions_file):
|
||||
""" Computes the next available API version number.
|
||||
"""
|
||||
major_version = int(VersionFormatter().get_chrome_major_version())
|
||||
next_revision = get_next_api_revision(api_versions_file, major_version)
|
||||
if next_revision < 0:
|
||||
return None
|
||||
|
||||
return version_make(major_version, next_revision)
|
||||
|
||||
|
||||
def git_grep_next(cef_dir):
|
||||
cmd = "grep --no-color -n -E (CEF_NEXT|CEF_NEXT)|=next -- :!include/cef_api_hash.h *.h"
|
||||
return exec_git_cmd(cmd, cef_dir)
|
||||
|
||||
|
||||
def find_next_usage(cpp_header_dir):
|
||||
cef_dir = os.path.abspath(os.path.join(cpp_header_dir, os.pardir))
|
||||
result = git_grep_next(cef_dir)
|
||||
if result is None:
|
||||
return False
|
||||
|
||||
sys.stderr.write('ERROR: NEXT usage found in CEF headers:\n\n' + result +
|
||||
'\n\nFix manually or run with --replace-next.\n')
|
||||
return True
|
||||
|
||||
|
||||
def replace_next_usage(file, linenums, as_variable, as_metadata):
|
||||
assert len(linenums) > 0
|
||||
|
||||
contents = read_file(file)
|
||||
if contents is None:
|
||||
sys.stderr.write('ERROR: Failed to read file %s\n' % file)
|
||||
return 0
|
||||
|
||||
lines = contents.split('\n')
|
||||
changect = 0
|
||||
|
||||
messages = []
|
||||
|
||||
for num in linenums:
|
||||
idx = num - 1
|
||||
if idx < 0 or idx >= len(lines):
|
||||
sys.stderr.write('ERROR: Invalid line number %d in file %s\n' % (num,
|
||||
file))
|
||||
return 0
|
||||
|
||||
line = lines[idx]
|
||||
|
||||
replaced = False
|
||||
if line.find('CEF_NEXT') >= 0:
|
||||
line = line.replace('CEF_NEXT', as_variable)
|
||||
replaced = True
|
||||
if line.find('=next') >= 0:
|
||||
line = line.replace('=next', '=' + as_metadata)
|
||||
replaced = True
|
||||
|
||||
if replaced:
|
||||
lines[idx] = line
|
||||
changect += 1
|
||||
else:
|
||||
messages.append(
|
||||
'WARNING: No NEXT instances found on line number %d' % num)
|
||||
|
||||
if changect > 0 and write_file(file, '\n'.join(lines)):
|
||||
messages.append('Replaced %d of %d NEXT instances' % (changect,
|
||||
len(linenums)))
|
||||
else:
|
||||
changect = 0
|
||||
|
||||
if len(messages) > 0:
|
||||
print('For file %s:' % file)
|
||||
for msg in messages:
|
||||
print(' %s' % msg)
|
||||
print()
|
||||
|
||||
return changect
|
||||
|
||||
|
||||
def find_replace_next_usage(cpp_header_dir, next_version):
|
||||
cef_dir = os.path.abspath(os.path.join(cpp_header_dir, os.pardir))
|
||||
result = git_grep_next(cef_dir)
|
||||
if result is None:
|
||||
return 0
|
||||
|
||||
print('Attempting to replace NEXT usage with %s in CEF headers:\n' %
|
||||
next_version)
|
||||
print(result + '\n')
|
||||
|
||||
as_variable = version_as_variable(next_version)
|
||||
as_metadata = version_as_metadata(next_version)
|
||||
|
||||
files = {}
|
||||
|
||||
# Parse values like:
|
||||
# include/test/cef_translator_test.h:879:#if CEF_API_ADDED(CEF_NEXT)
|
||||
# include/test/cef_translator_test.h:883: /*--cef(added=next)--*/
|
||||
for line in result.split('\n'):
|
||||
parts = line.split(':', maxsplit=2)
|
||||
name = parts[0]
|
||||
linenum = int(parts[1])
|
||||
if not name in files:
|
||||
files[name] = [linenum]
|
||||
else:
|
||||
files[name].append(linenum)
|
||||
|
||||
for file, linenums in files.items():
|
||||
if replace_next_usage(
|
||||
os.path.join(cef_dir, file), linenums, as_variable,
|
||||
as_metadata) != len(linenums):
|
||||
sys.stderr.write('ERROR: Failed to replace all NEXT usage in %s\n' % file)
|
||||
return 1
|
||||
|
||||
# Sanity-check that all instances were fixed.
|
||||
if find_next_usage(cpp_header_dir):
|
||||
return 1
|
||||
|
||||
print('All NEXT instances successfully replaced.')
|
||||
return 0
|
||||
|
||||
|
||||
def exec_apply(cpp_header_dir, api_versions_file, api_untracked_file,
|
||||
next_version, debug_dir, apply_next, verbose):
|
||||
""" Updates untracked API hashes if necessary.
|
||||
Saves the hash for the next API version if |apply_next| is true.
|
||||
"""
|
||||
json_versions, json_untracked, initialized = \
|
||||
read_version_files(api_versions_file, api_untracked_file, True)
|
||||
if initialized:
|
||||
# Also need to generate hashes for the first version.
|
||||
apply_next = True
|
||||
json_versions['min'] = next_version
|
||||
|
||||
untracked_changed = False
|
||||
for version in UNTRACKED_VERSIONS:
|
||||
label = version_label(version)
|
||||
hashes = compute_api_hashes(cpp_header_dir, version, True, debug_dir,
|
||||
verbose)
|
||||
if not bool(hashes):
|
||||
sys.stderr.write('ERROR: Failed to process %s\n' % label)
|
||||
return 1
|
||||
|
||||
if version in json_untracked['hashes'] and same_api_hashes(
|
||||
hashes, json_untracked['hashes'][version]):
|
||||
print('Hashes for %s are unchanged.' % label)
|
||||
else:
|
||||
untracked_changed = True
|
||||
print('Updating hashes for %s.' % label)
|
||||
json_untracked['hashes'][version] = hashes
|
||||
|
||||
next_changed = apply_next
|
||||
if apply_next:
|
||||
next_label = version_label(next_version)
|
||||
|
||||
hashes = compute_api_hashes(cpp_header_dir, next_version, False, debug_dir,
|
||||
verbose)
|
||||
if not bool(hashes):
|
||||
sys.stderr.write('ERROR: Failed to process %s\n' % next_label)
|
||||
return 1
|
||||
|
||||
last_version = json_versions.get('last', None)
|
||||
if not last_version is None and last_version in json_versions['hashes']:
|
||||
if same_api_hashes(hashes, json_versions['hashes'][last_version]):
|
||||
print('Hashes for last %s are unchanged.' % version_label(last_version))
|
||||
next_changed = False
|
||||
|
||||
if next_changed:
|
||||
print('Adding hashes for %s.' % next_label)
|
||||
json_versions['last'] = next_version
|
||||
json_versions['hashes'][next_version] = hashes
|
||||
|
||||
if NEXT_VERSION in json_untracked['hashes'] and not \
|
||||
same_api_hashes(hashes, json_untracked['hashes'][NEXT_VERSION]):
|
||||
print('NOTE: Additional versions are available to generate.')
|
||||
|
||||
write_versions = next_changed or not os.path.isfile(api_versions_file)
|
||||
write_untracked = untracked_changed or not os.path.isfile(api_untracked_file)
|
||||
|
||||
if not write_versions and not write_untracked:
|
||||
print('No hash updates required.')
|
||||
return -1
|
||||
|
||||
if write_versions and not write_json_file(
|
||||
api_versions_file, json_versions, quiet=False):
|
||||
return 1
|
||||
if write_untracked and not write_json_file(
|
||||
api_untracked_file, json_untracked, quiet=False):
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def exec_check(cpp_header_dir, api_versions_file, api_untracked_file, debug_dir,
|
||||
fast_check, force_update, skip_untracked, verbose):
|
||||
""" Checks existing API version hashes.
|
||||
Resaves all API hashes if |force_update| is true. Otherwise, hash
|
||||
changes are considered an error.
|
||||
"""
|
||||
assert not (fast_check and force_update)
|
||||
|
||||
json_versions, json_untracked, initialized = \
|
||||
read_version_files(api_versions_file, api_untracked_file, False)
|
||||
assert not initialized
|
||||
|
||||
versions = []
|
||||
len_versioned_existing = len_versioned_checked = len_versioned_failed = 0
|
||||
len_untracked_existing = len_untracked_checked = len_untracked_failed = 0
|
||||
|
||||
if not json_versions is None:
|
||||
keys = json_versions['hashes'].keys()
|
||||
len_versioned_existing = len(keys)
|
||||
if len_versioned_existing > 0:
|
||||
if fast_check:
|
||||
# Only checking a subset of versions.
|
||||
for key in ('last', 'min'):
|
||||
if key in json_versions:
|
||||
version = json_versions[key]
|
||||
assert version in json_versions['hashes'], version
|
||||
versions.append(version)
|
||||
len_versioned_checked += 1
|
||||
else:
|
||||
versions.extend(keys)
|
||||
len_versioned_checked = len_versioned_existing
|
||||
|
||||
if not json_untracked is None:
|
||||
keys = json_untracked['hashes'].keys()
|
||||
len_untracked_existing = len(keys)
|
||||
if len_untracked_existing > 0 and not skip_untracked:
|
||||
versions.extend(keys)
|
||||
len_untracked_checked = len_untracked_existing
|
||||
|
||||
if len(versions) == 0:
|
||||
print('No hashes to check.')
|
||||
return 0
|
||||
|
||||
write_versions = False
|
||||
write_untracked = False
|
||||
|
||||
for version in versions:
|
||||
untracked = version in UNTRACKED_VERSIONS
|
||||
if untracked:
|
||||
stored_hashes = json_untracked['hashes'][version]
|
||||
else:
|
||||
stored_hashes = json_versions['hashes'][version]
|
||||
label = version_label(version)
|
||||
computed_hashes = compute_api_hashes(cpp_header_dir, version, True,
|
||||
debug_dir, verbose)
|
||||
if not bool(computed_hashes):
|
||||
sys.stderr.write('ERROR: Failed to process %s\n' % label)
|
||||
return 1
|
||||
if not same_api_hashes(computed_hashes, stored_hashes):
|
||||
if force_update:
|
||||
print('Updating hashes for %s' % label)
|
||||
if untracked:
|
||||
json_untracked['hashes'][version] = computed_hashes
|
||||
write_untracked = True
|
||||
else:
|
||||
json_versions['hashes'][version] = computed_hashes
|
||||
write_versions = True
|
||||
else:
|
||||
sys.stderr.write('ERROR: Hashes for %s do not match!\n' % label)
|
||||
if untracked:
|
||||
len_untracked_failed += 1
|
||||
else:
|
||||
len_versioned_failed += 1
|
||||
|
||||
len_failed = len_untracked_failed + len_versioned_failed
|
||||
if len_failed == 0:
|
||||
if write_versions and not write_json_file(
|
||||
api_versions_file, json_versions, quiet=False):
|
||||
return 1
|
||||
if write_untracked and not write_json_file(
|
||||
api_untracked_file, json_untracked, quiet=False):
|
||||
return 1
|
||||
|
||||
if write_versions:
|
||||
print('WARNING: This change can break back/forward binary compatibility.')
|
||||
else:
|
||||
sys.stderr.write('ERROR: %d hashes checked and failed\n' % len_failed)
|
||||
|
||||
print('%d hashes checked and match (%d/%d versioned, %d/%d untracked).' %
|
||||
(len(versions) - len_failed,
|
||||
len_versioned_checked - len_versioned_failed, len_versioned_existing,
|
||||
len_untracked_checked - len_untracked_failed, len_untracked_existing))
|
||||
|
||||
return 0 if len_failed == 0 else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from optparse import OptionParser
|
||||
|
||||
desc = """
|
||||
This utility manages CEF API versions.
|
||||
"""
|
||||
|
||||
epilog = """
|
||||
Call this utility without arguments after modifying header files in the CEF
|
||||
include/ directory. Translated files will be updated if necessary.
|
||||
|
||||
If translated files have changed, or when running with -u, unversioned API
|
||||
hashes (next and experimental) will be checked and potentially updated.
|
||||
|
||||
If translated files have changed, or when running with -c, versioned and
|
||||
unversioned API hashes will be checked. Any changes to versioned API hashes
|
||||
can break back/forward binary compatibility and are considered an error.
|
||||
|
||||
API under development will use placeholder values like CEF_NEXT, added=next,
|
||||
removed=next in CEF header files. This utility can replace those placeholders
|
||||
with an actual new version and generate the associated versioned API hashes.
|
||||
|
||||
Run with -n to output the next available API version.
|
||||
|
||||
Run with -a to apply the next available API version.
|
||||
|
||||
For complete usage details see
|
||||
https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
|
||||
|
||||
"""
|
||||
|
||||
class CustomParser(OptionParser):
|
||||
|
||||
def format_epilog(self, formatter):
|
||||
return self.epilog
|
||||
|
||||
parser = CustomParser(description=desc, epilog=epilog)
|
||||
parser.add_option(
|
||||
'--debug-dir',
|
||||
dest='debugdir',
|
||||
metavar='DIR',
|
||||
help='intermediate directory for easy debugging')
|
||||
parser.add_option(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
dest='verbose',
|
||||
default=False,
|
||||
help='output detailed status information')
|
||||
parser.add_option(
|
||||
'-u',
|
||||
'--update',
|
||||
action='store_true',
|
||||
dest='update',
|
||||
default=False,
|
||||
help='update next and unversioned API hashes')
|
||||
parser.add_option(
|
||||
'-n',
|
||||
'--next',
|
||||
action='store_true',
|
||||
dest='next',
|
||||
default=False,
|
||||
help='output the next available API version')
|
||||
parser.add_option(
|
||||
'-a',
|
||||
'--apply-next',
|
||||
action='store_true',
|
||||
dest='apply',
|
||||
default=False,
|
||||
help='add a hash for the next available API version')
|
||||
parser.add_option(
|
||||
'-c',
|
||||
'--check',
|
||||
action='store_true',
|
||||
dest='check',
|
||||
default=False,
|
||||
help='check hashes for existing API versions')
|
||||
parser.add_option(
|
||||
'--fast-check',
|
||||
action='store_true',
|
||||
dest='fastcheck',
|
||||
default=False,
|
||||
help=
|
||||
'only check minimum, last, next and experimental API hashes (use with -u, -a or -c)'
|
||||
)
|
||||
parser.add_option(
|
||||
'--replace-next',
|
||||
action='store_true',
|
||||
dest='replacenext',
|
||||
default=False,
|
||||
help='replace NEXT usage in CEF headers (use with -a)')
|
||||
parser.add_option(
|
||||
'--replace-next-version',
|
||||
dest='replacenextversion',
|
||||
metavar='VERSION',
|
||||
help='replace NEXT usage with this value (use with --replace-next)')
|
||||
parser.add_option(
|
||||
'--force-update',
|
||||
action='store_true',
|
||||
dest='forceupdate',
|
||||
default=False,
|
||||
help='force update all API hashes (use with -c)')
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
script_dir = os.path.dirname(__file__)
|
||||
cef_dir = os.path.abspath(os.path.join(script_dir, os.pardir))
|
||||
|
||||
cpp_header_dir = os.path.join(cef_dir, 'include')
|
||||
if not os.path.isdir(cpp_header_dir):
|
||||
sys.stderr.write(
|
||||
'ERROR: Missing %s directory is required\n' % cpp_header_dir)
|
||||
sys.exit(1)
|
||||
|
||||
api_versions_file = os.path.join(cef_dir, VERSIONS_JSON_FILE)
|
||||
api_untracked_file = os.path.join(cef_dir, UNTRACKED_JSON_FILE)
|
||||
|
||||
mode_ct = options.update + options.next + options.apply + options.check
|
||||
if mode_ct > 1:
|
||||
sys.stderr.write(
|
||||
'ERROR: Choose a single execution mode (-u, -n, -a or -c)\n')
|
||||
parser.print_help(sys.stdout)
|
||||
sys.exit(1)
|
||||
|
||||
next_version = compute_next_api_verson(api_versions_file)
|
||||
if next_version is None:
|
||||
sys.exit(1)
|
||||
|
||||
if options.next:
|
||||
print(next_version)
|
||||
sys.exit(0)
|
||||
|
||||
will_apply_next = options.apply or not os.path.isfile(api_versions_file)
|
||||
if will_apply_next:
|
||||
if options.replacenext:
|
||||
replace_version = options.replacenextversion
|
||||
if replace_version is None:
|
||||
replace_version = next_version
|
||||
elif not version_valid_for_next(replace_version, next_version):
|
||||
sys.stderr.write('ERROR: Invalid value for --replace-next-version\n')
|
||||
sys.exit(1)
|
||||
result = find_replace_next_usage(cpp_header_dir, replace_version)
|
||||
if result != 0:
|
||||
sys.exit(result)
|
||||
elif find_next_usage(cpp_header_dir):
|
||||
sys.exit(1)
|
||||
|
||||
changed = translate(cef_dir, verbose=options.verbose) > 0
|
||||
skip_untracked = False
|
||||
|
||||
if options.update or will_apply_next or changed or not os.path.isfile(
|
||||
api_untracked_file):
|
||||
skip_untracked = True
|
||||
if exec_apply(
|
||||
cpp_header_dir,
|
||||
api_versions_file,
|
||||
api_untracked_file,
|
||||
next_version,
|
||||
options.debugdir,
|
||||
apply_next=options.apply,
|
||||
verbose=options.verbose) > 0:
|
||||
# Apply failed.
|
||||
sys.exit(1)
|
||||
elif not options.check:
|
||||
print('Nothing to do.')
|
||||
sys.exit(0)
|
||||
|
||||
sys.exit(
|
||||
exec_check(
|
||||
cpp_header_dir,
|
||||
api_versions_file,
|
||||
api_untracked_file,
|
||||
options.debugdir,
|
||||
options.fastcheck and not options.forceupdate,
|
||||
options.check and options.forceupdate,
|
||||
skip_untracked,
|
||||
verbose=options.verbose))
|
154
tools/version_util.py
Normal file
154
tools/version_util.py
Normal file
@@ -0,0 +1,154 @@
|
||||
# Copyright (c) 2024 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
|
||||
from __future__ import print_function
|
||||
from file_util import read_json_file
|
||||
|
||||
# Experimental version. Always the last value.
|
||||
EXP_VERSION = '999999'
|
||||
EXP_NAME = 'EXPERIMENTAL'
|
||||
|
||||
# Next version. Always the next to last value.
|
||||
NEXT_VERSION = '999998'
|
||||
NEXT_NAME = 'NEXT'
|
||||
|
||||
UNTRACKED_VERSIONS = (EXP_VERSION, NEXT_VERSION)
|
||||
UNTRACKED_NAMES = (EXP_NAME, NEXT_NAME)
|
||||
|
||||
VERSIONS_JSON_FILE = 'cef_api_versions.json'
|
||||
UNTRACKED_JSON_FILE = 'cef_api_untracked.json'
|
||||
|
||||
|
||||
def version_make(major_version, revision):
|
||||
""" Make a tracked version from components. """
|
||||
# 9999 is reserved for untracked placeholder values. This allows for ~898 years
|
||||
# of Chromium major versions at the current (end of 2024) rate of 11 per year.
|
||||
# If this breaks for you please file an issue via Ouija board and/or psychic medium.
|
||||
assert major_version > 0 and major_version < 9999, major_version
|
||||
assert revision >= 0 and revision <= 99, revision
|
||||
if major_version < 1000:
|
||||
return '%03d%02d' % (major_version, revision)
|
||||
return '%d%02d' % (major_version, revision)
|
||||
|
||||
|
||||
def version_tracked(version):
|
||||
""" Returns true if version is in tracked format. """
|
||||
return (len(version) == 5 or len(version) == 6) and version.isnumeric() and \
|
||||
not version in UNTRACKED_VERSIONS
|
||||
|
||||
|
||||
def version_parse(version):
|
||||
""" Parse a tracked version into components. """
|
||||
assert version_tracked(version), version
|
||||
split = 3 if len(version) == 5 else 4
|
||||
return (int(version[0:split]), int(version[split:]))
|
||||
|
||||
|
||||
def version_valid(version):
|
||||
""" Returns true if version is valid. """
|
||||
# Untracked versions must be referenced by name instead of number.
|
||||
return version in UNTRACKED_NAMES or version_tracked(version)
|
||||
|
||||
|
||||
def version_valid_for_next(version, ref_version, allow_exp=True):
|
||||
""" Returns true if version is valid as a replacement for NEXT. """
|
||||
version = version.upper()
|
||||
if allow_exp and version == EXP_NAME:
|
||||
return True
|
||||
# Must be valid and not NEXT.
|
||||
if not version_valid(version) or version == NEXT_NAME:
|
||||
return False
|
||||
# Must be >= ref_version.
|
||||
if version_as_numeric(version) < int(ref_version):
|
||||
return False
|
||||
# Must have the same major version number as ref_version.
|
||||
return version_parse(version)[0] == version_parse(ref_version)[0]
|
||||
|
||||
|
||||
def read_version_last(api_versions_file):
|
||||
json_versions = read_json_file(api_versions_file)
|
||||
if not bool(json_versions):
|
||||
return None
|
||||
assert 'last' in json_versions, api_versions_file
|
||||
return json_versions['last']
|
||||
|
||||
|
||||
def read_version_files(api_versions_file,
|
||||
api_untracked_file,
|
||||
initialize,
|
||||
combine=False):
|
||||
initialized = False
|
||||
|
||||
if combine:
|
||||
initialize = True
|
||||
|
||||
json_versions = read_json_file(api_versions_file)
|
||||
if not bool(json_versions):
|
||||
if initialize:
|
||||
json_versions = {
|
||||
'hashes': {},
|
||||
}
|
||||
initialized = True
|
||||
else:
|
||||
json_version = None
|
||||
else:
|
||||
assert 'hashes' in json_versions, api_versions_file
|
||||
assert 'last' in json_versions, api_versions_file
|
||||
assert 'min' in json_versions, api_versions_file
|
||||
|
||||
json_untracked = read_json_file(api_untracked_file)
|
||||
if not bool(json_untracked):
|
||||
if initialize:
|
||||
json_untracked = {
|
||||
'hashes': {},
|
||||
}
|
||||
else:
|
||||
json_untracked = None
|
||||
else:
|
||||
assert 'hashes' in json_untracked, api_untracked_file
|
||||
for version in json_untracked['hashes']:
|
||||
assert version in UNTRACKED_VERSIONS, api_untracked_file
|
||||
|
||||
if combine:
|
||||
if bool(json_untracked['hashes']):
|
||||
json_versions['hashes'].update(json_untracked['hashes'])
|
||||
return (json_versions, initialized)
|
||||
|
||||
return (json_versions, json_untracked, initialized)
|
||||
|
||||
|
||||
def version_label(version):
|
||||
if version == EXP_VERSION or version == EXP_NAME:
|
||||
return 'experimental version'
|
||||
if version == NEXT_VERSION or version == NEXT_NAME:
|
||||
return 'next version'
|
||||
return 'version ' + version
|
||||
|
||||
|
||||
def version_as_numeric(version):
|
||||
""" Returns version as a numeric value. """
|
||||
version = version.upper()
|
||||
assert version_valid(version), version
|
||||
if version == EXP_NAME:
|
||||
version = EXP_VERSION
|
||||
elif version == NEXT_NAME:
|
||||
version = NEXT_VERSION
|
||||
return int(version)
|
||||
|
||||
|
||||
def version_as_variable(version):
|
||||
""" Returns version as a variable for use in C/C++ files. """
|
||||
version = version.upper()
|
||||
assert version_valid(version), version
|
||||
if not version.isnumeric():
|
||||
return 'CEF_' + version
|
||||
return version
|
||||
|
||||
|
||||
def version_as_metadata(version):
|
||||
""" Returns version as metadata for comments in C++ header files. """
|
||||
version = version.upper()
|
||||
assert version_valid(version), version
|
||||
return version.lower()
|
Reference in New Issue
Block a user