[PATCH 1/2] scanner: Add --visibility flag for setting symbol visibility

Jonas Ådahl jadahl at gmail.com
Tue Jul 25 10:39:56 UTC 2017


Add a --visibility flag that enables the user to tweak the visibility
of the symbols generated by wayland-scanner. Three alternatives are
exposed:

'export': as has always been done up until now, export the symbols
using WL_EXPORT, making making them exposed externally. This is the
default in order to not break backward compatibility.

'compiler-default': use whatever visibility the compiler defaults to.
This is most likely the most visibility that protocol implementations
or users actually wants, as it doesn't expose any unwanted
implementation details.

'static': each symbol will only be visible to the compilation unit it
is included in. This means that a protocol implementations and users
needs to include both the 'code' file and either the 'client-header' or
'server-header' (or both) in the source file implementing or using the
protocol in question.

Using 'static' is a method to avoid situations where otherwise exposed
symbols of different protocols would conflict, for example if they have
the same interface name.

When no visibility is specified, 'export' is assumed, but a warning is
printed to stderr, as it is unlikely that 'export' is what is actually
desired.

Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---
 Makefile.am   |  10 ++---
 src/scanner.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 114 insertions(+), 20 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index d0c8bd3..d570525 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -97,19 +97,19 @@ nodist_libwayland_client_la_SOURCES =		\
 pkgconfig_DATA += src/wayland-client.pc src/wayland-server.pc
 
 protocol/%-protocol.c : $(top_srcdir)/protocol/%.xml
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code < $< > $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -Vexport code < $< > $@
 
 protocol/%-server-protocol.h : $(top_srcdir)/protocol/%.xml
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header < $< > $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -Vexport server-header < $< > $@
 
 protocol/%-client-protocol.h : $(top_srcdir)/protocol/%.xml
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header < $< > $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -Vexport client-header < $< > $@
 
 protocol/%-server-protocol-core.h : $(top_srcdir)/protocol/%.xml
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header -c < $< > $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -Vexport server-header -c < $< > $@
 
 protocol/%-client-protocol-core.h : $(top_srcdir)/protocol/%.xml
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header -c < $< > $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -Vexport client-header -c < $< > $@
 
 BUILT_SOURCES =					\
 	$(nodist_libwayland_server_la_SOURCES)	\
diff --git a/src/scanner.c b/src/scanner.c
index 517068c..d9152e3 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -57,6 +57,12 @@ enum side {
 	SERVER,
 };
 
+enum visibility {
+	VISIBILITY_EXPORT,
+	VISIBILITY_COMPILER_DEFAULT,
+	VISIBILITY_STATIC
+};
+
 static int
 usage(int ret)
 {
@@ -72,7 +78,16 @@ usage(int ret)
 			"                                 the scanner was built against.\n"
 		        "    -c,  --include-core-only     include the core version of the headers,\n"
 	                "                                 that is e.g. wayland-client-core.h instead\n"
-	                "                                 of wayland-client.h.\n");
+	                "                                 of wayland-client.h.\n"
+			"    -V,  --visibility=[export|compiler-default|static]\n"
+			"                                 select what type of visibility protocol\n"
+			"                                 symbols should have. 'export' will cause the\n"
+			"                                 symbols to be exported, 'compiler-default'\n"
+			"                                 will use the compiler default (often visible\n"
+			"                                 only within the same DSO), 'static' will make\n"
+			"                                 all symbols static (note that the file\n"
+			"                                 generated with 'code' must be included in the\n"
+			"                                 same file as the symbols are used\n");
 	exit(ret);
 }
 
@@ -226,6 +241,7 @@ struct entry {
 };
 
 struct parse_context {
+	enum visibility visibility;
 	struct location loc;
 	XML_Parser parser;
 	struct protocol *protocol;
@@ -1507,11 +1523,14 @@ 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;
 	const char *s = (side == SERVER) ? "SERVER" : "CLIENT";
+	const char *symbol_decl_tag = NULL;
 	char **p, *prev;
 
 	printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
@@ -1556,6 +1575,18 @@ emit_header(struct protocol *protocol, enum side side)
 	wl_array_release(&types);
 	printf("\n");
 
+	switch (ctx->visibility) {
+	case VISIBILITY_EXPORT:
+		symbol_decl_tag = "extern ";
+		break;
+	case VISIBILITY_COMPILER_DEFAULT:
+		symbol_decl_tag = "";
+		break;
+	case VISIBILITY_STATIC:
+		symbol_decl_tag = "static ";
+		break;
+	}
+
 	wl_list_for_each(i, &protocol->interface_list, link) {
 		printf("/**\n"
 		       " * @page page_iface_%s %s\n",
@@ -1575,8 +1606,9 @@ emit_header(struct protocol *protocol, enum side side)
 		if (i->description && i->description->text)
 			format_text_to_comment(i->description->text, false);
 		printf(" */\n");
-		printf("extern const struct wl_interface "
-		       "%s_interface;\n", i->name);
+		printf("%sconst struct wl_interface "
+		       "%s_interface;\n",
+		       symbol_decl_tag, i->name);
 	}
 
 	printf("\n");
@@ -1713,11 +1745,13 @@ 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;
 	char **p, *prev;
+	const char *visibility_tag = NULL;
+	const char *symbol_decl_tag = NULL;
 
 	printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
 
@@ -1728,6 +1762,18 @@ emit_code(struct protocol *protocol)
 	       "#include <stdint.h>\n"
 	       "#include \"wayland-util.h\"\n\n");
 
+	switch (ctx->visibility) {
+	case VISIBILITY_EXPORT:
+		symbol_decl_tag = "extern ";
+		break;
+	case VISIBILITY_COMPILER_DEFAULT:
+		symbol_decl_tag = "";
+		break;
+	case VISIBILITY_STATIC:
+		symbol_decl_tag = "static ";
+		break;
+	}
+
 	wl_array_init(&types);
 	wl_list_for_each(i, &protocol->interface_list, link) {
 		emit_types_forward_declarations(protocol, &i->request_list, &types);
@@ -1738,7 +1784,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("%sconst struct wl_interface %s_interface;\n",
+		       symbol_decl_tag, *p);
 		prev = *p;
 	}
 	wl_array_release(&types);
@@ -1752,14 +1799,26 @@ emit_code(struct protocol *protocol)
 	}
 	printf("};\n\n");
 
+	switch (ctx->visibility) {
+	case VISIBILITY_EXPORT:
+		visibility_tag = "WL_EXPORT ";
+		break;
+	case VISIBILITY_COMPILER_DEFAULT:
+		visibility_tag = "";
+		break;
+	case VISIBILITY_STATIC:
+		visibility_tag = "static ";
+		break;
+	}
 	wl_list_for_each_safe(i, next, &protocol->interface_list, link) {
 
 		emit_messages(&i->request_list, i, "requests");
 		emit_messages(&i->event_list, i, "events");
 
-		printf("WL_EXPORT const struct wl_interface "
+		printf("%sconst struct wl_interface "
 		       "%s_interface = {\n"
 		       "\t\"%s\", %d,\n",
+		       visibility_tag,
 		       i->name, i->name, i->version);
 
 		if (!wl_list_empty(&i->request_list))
@@ -1790,12 +1849,32 @@ free_protocol(struct protocol *protocol)
 	free_description(protocol->description);
 }
 
+static int
+parse_visibility_str(const char *visibility_str,
+		     enum visibility *visibility)
+{
+	if (strcmp(visibility_str, "export") == 0) {
+		*visibility = VISIBILITY_EXPORT;
+	} else if (strcmp(visibility_str, "compiler-default") == 0) {
+		*visibility = VISIBILITY_COMPILER_DEFAULT;
+	} else if (strcmp(visibility_str, "static") == 0) {
+		*visibility = VISIBILITY_STATIC;
+	} else {
+		fprintf(stderr, "Error: invalid visibility string '%s'\n",
+			visibility_str);
+		return -1;
+	}
+
+	return 0;
+}
+
 int main(int argc, char *argv[])
 {
 	struct parse_context ctx;
 	struct protocol protocol;
 	FILE *input = stdin;
 	char *input_filename = NULL;
+	char *visibility_str = NULL;
 	int len;
 	void *buf;
 	bool help = false;
@@ -1803,6 +1882,7 @@ int main(int argc, char *argv[])
 	bool version = false;
 	bool fail = false;
 	int opt;
+	enum visibility visibility = 0;
 	enum {
 		CLIENT_HEADER,
 		SERVER_HEADER,
@@ -1810,14 +1890,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' },
+		{ "visibility",        required_argument, NULL, 'V' },
+		{ 0,                   0,                 NULL, 0 }
 	};
 
 	while (1) {
-		opt = getopt_long(argc, argv, "hvc", options, NULL);
+		opt = getopt_long(argc, argv, "hvcV:", options, NULL);
 
 		if (opt == -1)
 			break;
@@ -1832,6 +1913,9 @@ int main(int argc, char *argv[])
 		case 'c':
 			core_headers = true;
 			break;
+		case 'V':
+			visibility_str = optarg;
+			break;
 		default:
 			fail = true;
 			break;
@@ -1858,6 +1942,15 @@ int main(int argc, char *argv[])
 	else
 		usage(EXIT_FAILURE);
 
+	if (!visibility_str) {
+		fprintf(stderr,
+			"Warning: protocol symbols will be exported, "
+			"make sure this is desired.\n");
+		visibility = VISIBILITY_EXPORT;
+	} else if (parse_visibility_str(visibility_str, &visibility) != 0) {
+		usage(EXIT_FAILURE);
+	}
+
 	if (argc == 3) {
 		input_filename = argv[1];
 		input = fopen(input_filename, "r");
@@ -1882,6 +1975,7 @@ int main(int argc, char *argv[])
 	/* initialize context */
 	memset(&ctx, 0, sizeof ctx);
 	ctx.protocol = &protocol;
+	ctx.visibility = visibility;
 	if (input == stdin)
 		ctx.loc.filename = "<stdin>";
 	else
@@ -1931,13 +2025,13 @@ 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;
 	}
 
-- 
2.13.0



More information about the wayland-devel mailing list