This repository was archived by the owner on Jan 30, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
vm_tools: Adds sommelier shim gen files
+ Adds scripts and template files to generate wayland shims. * Modifies build scripts to generate and build these files BUG=b:255439799 TEST=CQ - This is generating test infra stuff. Cq-Depend: chromium:4369582, chrome-internal:5651758 Change-Id: Ice996b9e985d6d85a6ffc762ee9629c4e48d8fef Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/4349388 Reviewed-by: Chloe Pelling <[email protected]> Tested-by: Justin Huang <[email protected]> Reviewed-by: Nic Hollingum <[email protected]> Commit-Queue: Justin Huang <[email protected]>
- Loading branch information
Justin Huang
authored and
Chromeos LUCI
committed
Mar 27, 2023
1 parent
fa86f5b
commit 2528898
Showing
7 changed files
with
390 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
#!/usr/bin/env python3 | ||
# Copyright 2023 The ChromiumOS Authors | ||
# Use of this source code is governed by a BSD-style license that can be | ||
# found in the LICENSE file. | ||
|
||
"""A C++ code generator of Wayland protocol shims.""" | ||
|
||
# pylint: enable=import-error | ||
import os | ||
import sys | ||
from xml.etree import ElementTree | ||
|
||
# pylint: disable=import-error | ||
from jinja2 import Template | ||
|
||
|
||
def CppTypeForWaylandEventType(xml_type_string, interface): | ||
"""Generates the type for a wayland event argument.""" | ||
if xml_type_string == "new_id" or xml_type_string == "object": | ||
return "struct wl_resource *" | ||
else: | ||
return CppTypeForWaylandType(xml_type_string, interface) | ||
|
||
|
||
def CppTypeForWaylandType(xml_type_string, interface): | ||
"""Generates the type for generic wayland type.""" | ||
if xml_type_string == "int" or xml_type_string == "fd": | ||
return "int32_t" | ||
elif xml_type_string == "uint" or xml_type_string == "new_id": | ||
return "uint32_t" | ||
elif xml_type_string == "fixed": | ||
return "wl_fixed_t" | ||
elif xml_type_string == "string": | ||
return "const char *" | ||
elif xml_type_string == "object": | ||
return "struct %s *" % interface | ||
elif xml_type_string == "array": | ||
return "struct wl_array *" | ||
else: | ||
raise ValueError("Invalid Type conversion: %s" % xml_type_string) | ||
|
||
|
||
def GetRequestReturnType(args): | ||
"""Gets the return type of a Wayland request.""" | ||
for arg in args: | ||
if arg.attrib["type"] == "new_id": | ||
if "interface" in arg.attrib: | ||
return "struct %s *" % arg.attrib["interface"] | ||
else: | ||
return "void *" | ||
return "void" | ||
|
||
|
||
def RequestXmlToJinjaInput(request): | ||
"""Parses a <request> element into dictionary form for use of jinja template.""" | ||
method = {"name": request.attrib["name"], "args": [], "ret": ""} | ||
method["ret"] = GetRequestReturnType(request.findall("arg")) | ||
|
||
for arg in request.findall("arg"): | ||
if arg.attrib["type"] == "new_id": | ||
if not arg.attrib.get("interface"): | ||
method["args"].append( | ||
{ | ||
"type": "const struct wl_interface *", | ||
"name": "interface", | ||
} | ||
) | ||
method["args"].append({"type": "uint32_t", "name": "version"}) | ||
else: | ||
method["args"].append( | ||
{ | ||
"name": arg.attrib["name"], | ||
"type": CppTypeForWaylandType( | ||
arg.attrib["type"], arg.attrib.get("interface", "") | ||
), | ||
} | ||
) | ||
return method | ||
|
||
|
||
def EventXmlToJinjaInput(event): | ||
"""Parses an <event> element into dictionary for for use of jinja template.""" | ||
return { | ||
"name": event.attrib["name"], | ||
"args": [ | ||
{ | ||
"name": arg.attrib["name"], | ||
"type": CppTypeForWaylandEventType( | ||
arg.attrib["type"], arg.attrib.get("interface", "") | ||
), | ||
} | ||
for arg in event.findall("arg") | ||
], | ||
} | ||
|
||
|
||
def InterfaceXmlToJinjaInput(interface): | ||
"""Creates an interface dict for XML interface input.""" | ||
interf = { | ||
"name": "".join( | ||
[i.capitalize() for i in interface.attrib["name"].split("_")] | ||
) | ||
+ "Shim", | ||
"name_underscore": interface.attrib["name"], | ||
"methods": [ | ||
RequestXmlToJinjaInput(i) for i in interface.findall("request") | ||
], | ||
"events": [EventXmlToJinjaInput(i) for i in interface.findall("event")], | ||
} | ||
return interf | ||
|
||
|
||
def GenerateShims(in_xml, out_directory): | ||
"""Generates shims for Wayland Protocols.""" | ||
with open( | ||
os.path.dirname(os.path.abspath(__file__)) | ||
+ "/gen/protocol-shim.h.jinja2", | ||
encoding="utf-8", | ||
) as f: | ||
shim_template = Template(f.read()) | ||
with open( | ||
os.path.dirname(os.path.abspath(__file__)) | ||
+ "/gen/protocol-shim.cc.jinja2", | ||
encoding="utf-8", | ||
) as f: | ||
shim_impl_template = Template(f.read()) | ||
with open( | ||
os.path.dirname(os.path.abspath(__file__)) | ||
+ "/gen/mock-protocol-shim.h.jinja2", | ||
encoding="utf-8", | ||
) as f: | ||
mock_template = Template(f.read()) | ||
|
||
tree = ElementTree.parse(in_xml) | ||
root = tree.getroot() | ||
|
||
filename = os.path.basename(in_xml).split(".")[0] | ||
|
||
# Because some protocol files don't have the protocol name == file name, we | ||
# have to infer the name from the file name instead (gtk-shell :eyes:) | ||
protocol = { | ||
"interfaces": [ | ||
InterfaceXmlToJinjaInput(i) for i in root.findall("interface") | ||
], | ||
"name_hyphen": filename, | ||
"name_underscore": filename.replace("-", "_"), | ||
} | ||
|
||
with open( | ||
out_directory + "/" + protocol["name_hyphen"] + "-shim.h", | ||
"w", | ||
encoding="utf-8", | ||
) as f: | ||
f.write(shim_template.render(protocol=protocol)) | ||
|
||
with open( | ||
out_directory + "/" + protocol["name_hyphen"] + "-shim.cc", | ||
"w", | ||
encoding="utf-8", | ||
) as f: | ||
f.write(shim_impl_template.render(protocol=protocol)) | ||
|
||
with open( | ||
out_directory + "/mock-" + protocol["name_hyphen"] + "-shim.h", | ||
"w", | ||
encoding="utf-8", | ||
) as f: | ||
f.write(mock_template.render(protocol=protocol)) | ||
|
||
|
||
if __name__ == "__main__": | ||
source_xml = sys.argv[1] | ||
out_dir = sys.argv[2] | ||
|
||
GenerateShims(source_xml, out_dir) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Copyright 2023 The ChromiumOS Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
// NOTE: This code is automatically generated and any changes to this file will be overwritten. | ||
|
||
#ifndef VM_TOOLS_SOMMELIER_GEN_MOCK_{{ protocol.name_underscore | upper }}_SHIM_H_ | ||
#define VM_TOOLS_SOMMELIER_GEN_MOCK_{{ protocol.name_underscore | upper }}_SHIM_H_ | ||
|
||
#include "{{ protocol.name_hyphen }}-shim.h" | ||
|
||
{%- for interface in protocol.interfaces %} | ||
class Mock{{interface.name}} { | ||
public: | ||
{%- for method in interface.methods %} | ||
MOCK_METHOD({{ method.ret }}, {{ method.name }}, ({% for arg in method.args %}{{ arg.type }} {{ arg.name }}{% if not loop.last %},{% endif %}{% endfor %}), (override)); | ||
{% endfor -%} | ||
{%- for event in interface.events %} | ||
MOCK_METHOD(void, {{ event.name }}, ({% for arg in event.args %}{{ arg.type }} {{ arg.name }}{% if not loop.last %},{% endif %}{% endfor %}), (override)); | ||
{% endfor -%} | ||
}; | ||
{% endfor -%} | ||
|
||
#endif // VM_TOOLS_SOMMELIER_GEN_MOCK_{{ protocol.name_underscore | upper }}_SHIM_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright 2023 The ChromiumOS Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
// NOTE: This code is automatically generated and any changes to this file will be overwritten. | ||
|
||
#include "{{ protocol.name_hyphen }}-shim.h" | ||
|
||
{%- for interface in protocol.interfaces %} | ||
|
||
void {{ interface.name }}::set_user_data(struct {{interface.name_underscore}} *{{interface.name_underscore}}, void* user_data) { | ||
{{ interface.name_underscore }}_set_user_data({{ interface.name_underscore }}, user_data); | ||
} | ||
|
||
void* {{ interface.name }}::get_user_data(struct {{ interface.name_underscore }} *{{interface.name_underscore}}) { | ||
return {{ interface.name_underscore }}_get_user_data({{ interface.name_underscore }}); | ||
} | ||
|
||
{%- for method in interface.methods %} | ||
{{ method.ret }} {{ interface.name }}::{{method.name}}( | ||
struct {{ interface.name_underscore }} *{{ interface.name_underscore }}{% for arg in method.args %}, | ||
{{ arg.type }} {{ arg.name }}{%endfor%}) { | ||
{% if method.ret %}return {% endif %}{{ interface.name_underscore }}_{{ method.name }}({{ interface.name_underscore }}{% for arg in method.args %}, {{ arg.name }}{% endfor %}); | ||
} | ||
{% endfor -%} | ||
|
||
{%- for event in interface.events %} | ||
void {{ interface.name}}::send_{{event.name}}( | ||
struct wl_resource* resource{% for arg in event.args %}, | ||
{{ arg.type }} {{ arg.name }}{% endfor %}) { | ||
{{ interface.name_underscore }}_send_{{ event.name }}(resource{% for arg in event.args %}, {{ arg.name }}{% endfor %}); | ||
} | ||
{% endfor -%} | ||
|
||
|
||
static {{ interface.name }}* {{ interface.name_underscore }}_singleton = nullptr; | ||
|
||
{{ interface.name }}* {{ interface.name_underscore | lower }}_shim() { | ||
return {{ interface.name_underscore }}_singleton; | ||
} | ||
|
||
void set_{{ interface.name_underscore }}_shim ({{ interface.name }}* shim) { | ||
{{ interface.name_underscore }}_singleton = shim; | ||
} | ||
{% endfor -%} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
{# NOTE: This combines both the client and server APIs together because sommelier is both -#} | ||
// Copyright 2023 The ChromiumOS Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
// NOTE: This code is automatically generated and any changes to this file will be overwritten. | ||
|
||
#ifndef VM_TOOLS_SOMMELIER_GEN_{{ protocol.name_underscore | upper }}_SHIM_H_ | ||
#define VM_TOOLS_SOMMELIER_GEN_{{ protocol.name_underscore | upper }}_SHIM_H_ | ||
|
||
#include "{{ protocol.name_hyphen }}-client-protocol.h" // NOLINT(build/include_directory) | ||
#include "{{ protocol.name_hyphen }}-server-protocol.h" // NOLINT(build/include_directory) | ||
|
||
{# This generates a series of virtual functions which calls the underlying | ||
wayland protocol functions. It's mostly modelled off wayland-scanner, ref: | ||
https://chromium.googlesource.com/external/wayland/wayland/+/refs/heads/master/src/scanner.c#932 -#} | ||
{% for interface in protocol.interfaces %} | ||
class {{ interface.name }} { | ||
public: | ||
{{ interface.name }}() = default; | ||
{{ interface.name }}({{ interface.name }}&&) = delete; | ||
{{ interface.name }}& operator=({{ interface.name }}&&) = delete; | ||
|
||
{# Logic comes from wayland scanner -#} | ||
{# Stub logic -> https://chromium.googlesource.com/external/wayland/wayland/+/refs/heads/master/src/scanner.c#1007 -#} | ||
virtual void set_user_data(struct {{ interface.name_underscore }} *{{ interface.name_underscore}}, void *user_data); | ||
|
||
virtual void* get_user_data(struct {{ interface.name_underscore }} *{{ interface.name_underscore }}); | ||
|
||
{%- for method in interface.methods %} | ||
virtual {{ method.ret }} {{ method.name }}( | ||
struct {{ interface.name_underscore }} *{{ interface.name_underscore }}{% for arg in method.args %}, | ||
{{ arg.type }} {{ arg.name }}{% endfor %}); | ||
{% endfor -%} | ||
|
||
{# Event logic -> https://chromium.googlesource.com/external/wayland/wayland/+/refs/heads/master/src/scanner.c#1074 -#} | ||
{%- for event in interface.events %} | ||
virtual void send_{{ event.name }}( | ||
struct wl_resource * resource{% for arg in event.args %}, | ||
{{ arg.type }} {{arg.name}}{% endfor %}); | ||
{% endfor -%} | ||
}; | ||
|
||
{{ interface.name }}* {{ interface.name_underscore | lower }}_shim(); | ||
void set_{{ interface.name_underscore }}_shim ({{ interface.name }}* shim); | ||
{% endfor %} | ||
|
||
#endif // VM_TOOLS_SOMMELIER_GEN_{{ protocol.name_underscore | upper}}_SHIM_H_ |
Oops, something went wrong.