[PATCH wayland 2/3] scanner: Allow adding a prefix to exported symbols

Jonas Ådahl jadahl at gmail.com
Mon Jul 3 09:16:45 UTC 2017


Two different protocols may use interfaces with identical names.
Implementing support for both those protocols would result in symbol
clashes, as wayland-scanner generates symbols from the interface names.

Make it possible to avoiding these clashes by adding a way to add a
prefix to the symbols generated by wayland-scanner. Implementations
(servers and clients) can then use these prefix:ed symbols to implement
different objects with the same name.

Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---

Something like this would be needed if a compositor/client wants to implement
xdg-shell unstable v5 alongside xdg-shell stable, unless we want to rename all
our xdg-shell interfaces. Implementing xdg-shell unstable v6 alongside
xdg-shell stable does not have this issue.

See issue raised here:
https://lists.freedesktop.org/archives/wayland-devel/2017-June/034380.html


Jonas


 src/scanner.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 73 insertions(+), 21 deletions(-)

diff --git a/src/scanner.c b/src/scanner.c
index 517068c..00b5a84 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -228,6 +228,7 @@ struct entry {
 struct parse_context {
 	struct location loc;
 	XML_Parser parser;
+	char *symbol_prefix;
 	struct protocol *protocol;
 	struct interface *interface;
 	struct message *message;
@@ -1041,7 +1042,9 @@ emit_type(struct arg *a)
 }
 
 static void
-emit_stubs(struct wl_list *message_list, struct interface *interface)
+emit_stubs(struct parse_context *ctx,
+	   struct wl_list *message_list,
+	   struct interface *interface)
 {
 	struct message *m;
 	struct arg *a, *ret;
@@ -1168,11 +1171,12 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
 			printf("\tstruct wl_proxy *%s;\n\n"
 			       "\t%s = wl_proxy_marshal_constructor("
 			       "(struct wl_proxy *) %s,\n"
-			       "\t\t\t %s_%s, &%s_interface",
+			       "\t\t\t %s_%s, &%s%s_interface",
 			       ret->name, ret->name,
 			       interface->name,
 			       interface->uppercase_name,
 			       m->uppercase_name,
+			       ctx->symbol_prefix,
 			       ret->interface_name);
 		} else {
 			/* No args have type="new_id" */
@@ -1507,7 +1511,7 @@ emit_mainpage_blurb(const struct protocol *protocol, enum side side)
 }
 
 static void
-emit_header(struct protocol *protocol, enum side side)
+emit_header(struct parse_context *ctx, struct protocol *protocol, enum side side)
 {
 	struct interface *i, *i_next;
 	struct wl_array types;
@@ -1576,7 +1580,7 @@ emit_header(struct protocol *protocol, enum side side)
 			format_text_to_comment(i->description->text, false);
 		printf(" */\n");
 		printf("extern const struct wl_interface "
-		       "%s_interface;\n", i->name);
+		       "%s%s_interface;\n", ctx->symbol_prefix, i->name);
 	}
 
 	printf("\n");
@@ -1596,7 +1600,7 @@ emit_header(struct protocol *protocol, enum side side)
 			emit_opcodes(&i->request_list, i);
 			emit_opcode_versions(&i->event_list, i);
 			emit_opcode_versions(&i->request_list, i);
-			emit_stubs(&i->request_list, i);
+			emit_stubs(ctx, &i->request_list, i);
 		}
 
 		free_interface(i);
@@ -1619,7 +1623,9 @@ emit_null_run(struct protocol *protocol)
 }
 
 static void
-emit_types(struct protocol *protocol, struct wl_list *message_list)
+emit_types(struct parse_context *ctx,
+	   struct protocol *protocol,
+	   struct wl_list *message_list)
 {
 	struct message *m;
 	struct arg *a;
@@ -1639,7 +1645,8 @@ emit_types(struct protocol *protocol, struct wl_list *message_list)
 			case NEW_ID:
 			case OBJECT:
 				if (a->interface_name)
-					printf("\t&%s_interface,\n",
+					printf("\t&%s%s_interface,\n",
+					       ctx->symbol_prefix,
 					       a->interface_name);
 				else
 					printf("\tNULL,\n");
@@ -1713,7 +1720,7 @@ emit_messages(struct wl_list *message_list,
 }
 
 static void
-emit_code(struct protocol *protocol)
+emit_code(struct parse_context *ctx, struct protocol *protocol)
 {
 	struct interface *i, *next;
 	struct wl_array types;
@@ -1738,7 +1745,8 @@ emit_code(struct protocol *protocol)
 	wl_array_for_each(p, &types) {
 		if (prev && strcmp(*p, prev) == 0)
 			continue;
-		printf("extern const struct wl_interface %s_interface;\n", *p);
+		printf("extern const struct wl_interface %s%s_interface;\n",
+		       ctx->symbol_prefix, *p);
 		prev = *p;
 	}
 	wl_array_release(&types);
@@ -1747,8 +1755,8 @@ emit_code(struct protocol *protocol)
 	printf("static const struct wl_interface *types[] = {\n");
 	emit_null_run(protocol);
 	wl_list_for_each(i, &protocol->interface_list, link) {
-		emit_types(protocol, &i->request_list);
-		emit_types(protocol, &i->event_list);
+		emit_types(ctx, protocol, &i->request_list);
+		emit_types(ctx, protocol, &i->event_list);
 	}
 	printf("};\n\n");
 
@@ -1758,9 +1766,9 @@ emit_code(struct protocol *protocol)
 		emit_messages(&i->event_list, i, "events");
 
 		printf("WL_EXPORT const struct wl_interface "
-		       "%s_interface = {\n"
+		       "%s%s_interface = {\n"
 		       "\t\"%s\", %d,\n",
-		       i->name, i->name, i->version);
+		       ctx->symbol_prefix, i->name, i->name, i->version);
 
 		if (!wl_list_empty(&i->request_list))
 			printf("\t%d, %s_requests,\n",
@@ -1790,6 +1798,35 @@ free_protocol(struct protocol *protocol)
 	free_description(protocol->description);
 }
 
+static bool
+is_valid_symbol_prefix(char *symbol_prefix)
+{
+	int i, len;
+
+	len = strlen(symbol_prefix);
+	for (i = 0; i < len; i++) {
+		char c = symbol_prefix[i];
+
+		if (i == 0) {
+			if (isalpha(c))
+				continue;
+
+			return false;
+		} else {
+			if (isalpha(c))
+				continue;
+			if (isdigit(c))
+				continue;
+			if (c == '_')
+				continue;
+
+			return false;
+		}
+	}
+
+	return true;
+}
+
 int main(int argc, char *argv[])
 {
 	struct parse_context ctx;
@@ -1802,6 +1839,7 @@ int main(int argc, char *argv[])
 	bool core_headers = false;
 	bool version = false;
 	bool fail = false;
+	char *symbol_prefix = NULL;
 	int opt;
 	enum {
 		CLIENT_HEADER,
@@ -1810,14 +1848,15 @@ int main(int argc, char *argv[])
 	} mode;
 
 	static const struct option options[] = {
-		{ "help",              no_argument, NULL, 'h' },
-		{ "version",           no_argument, NULL, 'v' },
-		{ "include-core-only", no_argument, NULL, 'c' },
-		{ 0,                   0,           NULL, 0 }
+		{ "help",              no_argument,       NULL, 'h' },
+		{ "version",           no_argument,       NULL, 'v' },
+		{ "include-core-only", no_argument,       NULL, 'c' },
+		{ "symbol-prefix",     required_argument, NULL, 'p' },
+		{ 0,                   0,                 NULL, 0 }
 	};
 
 	while (1) {
-		opt = getopt_long(argc, argv, "hvc", options, NULL);
+		opt = getopt_long(argc, argv, "hvcp:", options, NULL);
 
 		if (opt == -1)
 			break;
@@ -1832,6 +1871,9 @@ int main(int argc, char *argv[])
 		case 'c':
 			core_headers = true;
 			break;
+		case 'p':
+			symbol_prefix = strdup(optarg);
+			break;
 		default:
 			fail = true;
 			break;
@@ -1858,6 +1900,14 @@ int main(int argc, char *argv[])
 	else
 		usage(EXIT_FAILURE);
 
+	if (!symbol_prefix)
+		symbol_prefix = strdup("");
+	if (!is_valid_symbol_prefix(symbol_prefix)) {
+		fprintf(stderr, "Symbol prefix '%s' not valid\n",
+			symbol_prefix);
+		exit(EXIT_FAILURE);
+	}
+
 	if (argc == 3) {
 		input_filename = argv[1];
 		input = fopen(input_filename, "r");
@@ -1882,6 +1932,7 @@ int main(int argc, char *argv[])
 	/* initialize context */
 	memset(&ctx, 0, sizeof ctx);
 	ctx.protocol = &protocol;
+	ctx.symbol_prefix = symbol_prefix;
 	if (input == stdin)
 		ctx.loc.filename = "<stdin>";
 	else
@@ -1931,16 +1982,17 @@ int main(int argc, char *argv[])
 
 	switch (mode) {
 		case CLIENT_HEADER:
-			emit_header(&protocol, CLIENT);
+			emit_header(&ctx, &protocol, CLIENT);
 			break;
 		case SERVER_HEADER:
-			emit_header(&protocol, SERVER);
+			emit_header(&ctx, &protocol, SERVER);
 			break;
 		case CODE:
-			emit_code(&protocol);
+			emit_code(&ctx, &protocol);
 			break;
 	}
 
+	free(symbol_prefix);
 	free_protocol(&protocol);
 	fclose(input);
 
-- 
2.13.0



More information about the wayland-devel mailing list