diff --git a/docs/reference/gio/glib-compile-resources.xml b/docs/reference/gio/glib-compile-resources.xml index 219ed7c72..5421f3d91 100644 --- a/docs/reference/gio/glib-compile-resources.xml +++ b/docs/reference/gio/glib-compile-resources.xml @@ -170,6 +170,16 @@ which is what does. + + + +By default code generated by embeds the +resource data as a string literal. When +is given, the data is only declared in the generated C file, and the data +has to be linked externally. + + + diff --git a/gio/glib-compile-resources.c b/gio/glib-compile-resources.c index 2c421b6a4..60ccdbf81 100644 --- a/gio/glib-compile-resources.c +++ b/gio/glib-compile-resources.c @@ -725,6 +725,7 @@ main (int argc, char **argv) gboolean generate_header = FALSE; gboolean manual_register = FALSE; gboolean internal = FALSE; + gboolean external_data = FALSE; gboolean generate_dependencies = FALSE; gboolean generate_phony_targets = FALSE; char *dependency_file = NULL; @@ -744,6 +745,7 @@ main (int argc, char **argv) { "generate-phony-targets", 0, 0, G_OPTION_ARG_NONE, &generate_phony_targets, N_("Include phony targets in the generated dependency file"), NULL }, { "manual-register", 0, 0, G_OPTION_ARG_NONE, &manual_register, N_("Don’t automatically create and register resource"), NULL }, { "internal", 0, 0, G_OPTION_ARG_NONE, &internal, N_("Don’t export functions; declare them G_GNUC_INTERNAL"), NULL }, + { "external-data", 0, 0, G_OPTION_ARG_NONE, &external_data, N_("Don’t embed resource data in the C file; assume it's linked externally instead"), NULL }, { "c-name", 0, 0, G_OPTION_ARG_STRING, &c_name, N_("C identifier name used for the generated source code"), NULL }, { NULL } }; @@ -1089,49 +1091,60 @@ main (int argc, char **argv) "\n", c_name_no_underscores); - /* For Visual Studio builds: Avoid surpassing the 65535-character limit for a string, GitLab issue #1580 */ - g_fprintf (file, "#ifdef _MSC_VER\n"); - g_fprintf (file, - "static const SECTION union { const guint8 data[%"G_GSIZE_FORMAT"]; const double alignment; void * const ptr;} %s_resource_data = { {\n", - data_size + 1 /* nul terminator */, c_name); - - for (i = 0; i < data_size; i++) + if (external_data) { - if (i % 16 == 0) - g_fprintf (file, " "); - g_fprintf (file, "0%3.3o", (int)data[i]); - if (i != data_size - 1) - g_fprintf (file, ", "); - if (i % 16 == 15 || i == data_size - 1) - g_fprintf (file, "\n"); + g_fprintf (file, + "extern const SECTION union { const guint8 data[%"G_GSIZE_FORMAT"]; const double alignment; void * const ptr;} %s_resource_data;" + "\n", + data_size, c_name); } + else + { + /* For Visual Studio builds: Avoid surpassing the 65535-character limit for a string, GitLab issue #1580 */ + g_fprintf (file, "#ifdef _MSC_VER\n"); + g_fprintf (file, + "static const SECTION union { const guint8 data[%"G_GSIZE_FORMAT"]; const double alignment; void * const ptr;} %s_resource_data = { {\n", + data_size + 1 /* nul terminator */, c_name); - g_fprintf (file, "} };\n"); + for (i = 0; i < data_size; i++) + { + if (i % 16 == 0) + g_fprintf (file, " "); + g_fprintf (file, "0%3.3o", (int)data[i]); + if (i != data_size - 1) + g_fprintf (file, ", "); + if (i % 16 == 15 || i == data_size - 1) + g_fprintf (file, "\n"); + } - /* For other compilers, use the long string approach */ - g_fprintf (file, "#else /* _MSC_VER */\n"); - g_fprintf (file, - "static const SECTION union { const guint8 data[%"G_GSIZE_FORMAT"]; const double alignment; void * const ptr;} %s_resource_data = {\n \"", - data_size + 1 /* nul terminator */, c_name); + g_fprintf (file, "} };\n"); - for (i = 0; i < data_size; i++) { - g_fprintf (file, "\\%3.3o", (int)data[i]); - if (i % 16 == 15) - g_fprintf (file, "\"\n \""); - } + /* For other compilers, use the long string approach */ + g_fprintf (file, "#else /* _MSC_VER */\n"); + g_fprintf (file, + "static const SECTION union { const guint8 data[%"G_GSIZE_FORMAT"]; const double alignment; void * const ptr;} %s_resource_data = {\n \"", + data_size + 1 /* nul terminator */, c_name); - g_fprintf (file, "\" };\n"); - g_fprintf (file, "#endif /* !_MSC_VER */\n"); + for (i = 0; i < data_size; i++) + { + g_fprintf (file, "\\%3.3o", (int)data[i]); + if (i % 16 == 15) + g_fprintf (file, "\"\n \""); + } + + g_fprintf (file, "\" };\n"); + g_fprintf (file, "#endif /* !_MSC_VER */\n"); + } g_fprintf (file, "\n" - "static GStaticResource static_resource = { %s_resource_data.data, sizeof (%s_resource_data.data) - 1 /* nul terminator */, NULL, NULL, NULL };\n" + "static GStaticResource static_resource = { %s_resource_data.data, sizeof (%s_resource_data.data)%s, NULL, NULL, NULL };\n" "%s GResource *%s_get_resource (void);\n" "GResource *%s_get_resource (void)\n" "{\n" " return g_static_resource_get_resource (&static_resource);\n" "}\n", - c_name, c_name, linkage, c_name, c_name); + c_name, c_name, (external_data ? "" : " - 1 /* nul terminator */"), linkage, c_name, c_name); if (manual_register) diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index db3247e37..e8baa0101 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -670,8 +670,21 @@ plugin_resources.c: test4.gresource.xml Makefile $(shell $(glib_compile_resource test.gresource: test.gresource.xml Makefile $(shell $(glib_compile_resources) --sourcedir=. --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/test.gresource.xml) $(AM_V_GEN) $(glib_compile_resources) --target=$@ --sourcedir=. --sourcedir=$(srcdir) $< -EXTRA_DIST += test.gresource.xml test1.txt test2.gresource.xml test2.txt test3.gresource.xml test3.txt test4.gresource.xml gen-big-test-resource.py +EXTRA_DIST += test.gresource.xml test1.txt test2.gresource.xml test2.txt test3.gresource.xml test3.txt test4.gresource.xml test5.gresource.xml gen-big-test-resource.py CLEANFILES += test-generated.txt test_resources.c test_resources2.[ch] plugin_resources.c test.gresource gresource-big-test.txt + +if OS_LINUX +test5.gresource: test5.gresource.xml Makefile $(shell $(glib_compile_resources) --sourcedir=. --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/test5.gresource.xml) + $(AM_V_GEN) $(glib_compile_resources) --target=$@ --sourcedir=. --sourcedir=$(srcdir) $< +test_resources_binary.c: test5.gresource.xml Makefile $(shell $(glib_compile_resources) --sourcedir=. --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/test5.gresource.xml) + $(AM_V_GEN) $(glib_compile_resources) --target=$@ --sourcedir=$(srcdir) --generate-source --c-name _g_binary_test1 $< +test_resources_binary_data.o: test5.gresource + $(AM_V_GEN) ld -r -b binary $< -o $@ +test_resources_binary_data2.o: test_resources_binary.o + $(AM_V_GEN) objcopy --add-symbol _g_binary_test1_resource_data=.data:0 -N _binary_test5_gresource_start -N _binary_test5_gresource_size -N _binary_test5_gresource_end $< $@ +nodist_resources_SOURCES += test_resources_binary_data2.o test_resources_binary.c +endif + endif # !CROSS_COMPILING BUILT_SOURCES += giotypefuncs.inc diff --git a/gio/tests/meson.build b/gio/tests/meson.build index c39d89803..5bbc07176 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -524,12 +524,67 @@ if not meson.is_cross_build() or meson.has_exe_wrapper() copy : true, install : false) - gio_tests += { - 'resources' : { - 'extra_sources' : [test_gresource, test_resources_c, test_resources2_c, - test_resources2_h], - }, - } + # Create object file containing resource data + # for testing the external data option + if build_machine.system() == 'linux' + test_gresource_binary = custom_target('test5.gresource', + input : 'test5.gresource.xml', + output : 'test5.gresource', + command : [glib_compile_resources, + '--target=@OUTPUT@', + '--sourcedir=' + meson.current_source_dir(), + '--sourcedir=' + meson.current_build_dir(), + '@INPUT@'], + install_dir : installed_tests_execdir, + install : installed_tests_enabled) + + # Create resource data file + test_resources_binary_c = custom_target('test_resources_binary.c', + input : 'test5.gresource.xml', + output : 'test_resources_binary.c', + command : [glib_compile_resources, + '--target=@OUTPUT@', + '--sourcedir=' + meson.current_source_dir(), + '--sourcedir=' + meson.current_build_dir(), + '--generate-source', + '--external-data', + '--c-name', '_g_binary_test1', + '@INPUT@']) + + # Create object file containing resource data + test_resources_binary = custom_target('test_resources.o', + input : test_gresource_binary, + output : 'test_resources.o', + command : ['ld', + '-r', + '-b','binary', + '@INPUT@', + '-o','@OUTPUT@']) + + # Rename symbol to match the one in the C file + test_resources_binary2 = custom_target('test_resources2.o', + input : test_resources_binary, + output : 'test_resources2.o', + command : ['objcopy', + '--add-symbol','_g_binary_test1_resource_data=.data:0', + '@INPUT@', + '@OUTPUT@']) + + gio_tests += { + 'resources' : { + 'extra_sources' : [test_gresource, test_resources_c, test_resources2_c, + test_resources2_h, test_resources_binary_c, + test_resources_binary2], + }, + } + else + gio_tests += { + 'resources' : { + 'extra_sources' : [test_gresource, test_resources_c, test_resources2_c, + test_resources2_h], + }, + } + endif endif foreach test_name, extra_args : gio_tests diff --git a/gio/tests/resources.c b/gio/tests/resources.c index 11f1f3f2c..719624514 100644 --- a/gio/tests/resources.c +++ b/gio/tests/resources.c @@ -558,6 +558,43 @@ test_resource_manual2 (void) g_resource_unref (resource); } +/* Test building resources with external data option, + * where data is linked in as binary instead of compiled in. + * Checks if resources are automatically registered and + * data can be found and read. */ +static void +test_resource_binary_linked (void) +{ + #ifndef __linux__ + g_test_skip ("--external-data test only works on Linux"); + return; + #else /* if __linux__ */ + GError *error = NULL; + gboolean found; + gsize size; + guint32 flags; + GBytes *data; + + found = g_resources_get_info ("/binary_linked/test1.txt", + G_RESOURCE_LOOKUP_FLAGS_NONE, + &size, &flags, &error); + g_assert_true (found); + g_assert_no_error (error); + g_assert_cmpint (size, ==, 6); + g_assert_cmpuint (flags, ==, 0); + + data = g_resources_lookup_data ("/binary_linked/test1.txt", + G_RESOURCE_LOOKUP_FLAGS_NONE, + &error); + g_assert_nonnull (data); + g_assert_no_error (error); + size = g_bytes_get_size (data); + g_assert_cmpint (size, ==, 6); + g_assert_cmpstr (g_bytes_get_data (data, NULL), ==, "test1\n"); + g_bytes_unref (data); + #endif /* if __linux__ */ +} + static void test_resource_module (void) { @@ -877,6 +914,7 @@ main (int argc, g_test_add_func ("/resource/automatic", test_resource_automatic); /* This only uses automatic resources too, so it tests the constructors and destructors */ g_test_add_func ("/resource/module", test_resource_module); + g_test_add_func ("/resource/binary-linked", test_resource_binary_linked); #endif g_test_add_func ("/resource/uri/query-info", test_uri_query_info); g_test_add_func ("/resource/uri/file", test_uri_file); diff --git a/gio/tests/test5.gresource.xml b/gio/tests/test5.gresource.xml new file mode 100644 index 000000000..8e81a5155 --- /dev/null +++ b/gio/tests/test5.gresource.xml @@ -0,0 +1,6 @@ + + + + test1.txt + +