Files
cef/tools/make_pack_header.py
Marshall Greenblatt dd81904a2f 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).
2025-01-08 17:19:43 -05:00

184 lines
4.4 KiB
Python

#!/usr/bin/env python
# Copyright (c) 2012 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.
"""
A simple utility function to merge pack resource files into a single resource file.
"""
from __future__ import absolute_import
from __future__ import print_function
from cef_parser import get_copyright
from file_util import *
import os
import re
import string
import sys
def _make_pack_header_segment(input, ids):
result = """
// ---------------------------------------------------------------------------
// From $FILE$:
"""
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:
# #define IDR_RESOURCE_NAME 12345
# [1] See https://crbug.com/684788#c18
regex = r'#define\s([A-Za-z0-9_]{1,})\s+'
if contents.find('ui::WhitelistedResource') > 0:
regex += r'.*<'
regex += r'([0-9]{1,})'
# identify the defines in the file
p = re.compile(regex)
list = p.findall(contents)
for name, id in list:
# If the same define exists in multiple files add a suffix.
if name in all_names:
all_names[name] += 1
name += '_%d' % all_names[name]
else:
all_names[name] = 1
ids[name] = id
return ids
def write_pack_header(out_header_file, out_inc_file, inputs):
# sort the input files by name
inputs = sorted(inputs, key=lambda path: os.path.split(path)[1])
all_names = {}
all_files = {}
# generate the file segments
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)
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)
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)
return retval1 #or retval2
def main(argv):
if len(argv) < 4:
print(
"Usage:\n %s <output_header_file> <output_inc_file> <input_file1> [input_file2] ... "
% argv[0])
sys.exit(-1)
write_pack_header(argv[1], argv[2], argv[3:])
if '__main__' == __name__:
main(sys.argv)