[glib: 1/2] glib-compile-resources: Add external data option



commit d04b9c371d277fa45ba20ad83642e57af50381e7
Author: Ninja-Koala <mail ninjakoa la>
Date:   Sun Sep 9 18:31:38 2018 +0200

    glib-compile-resources: Add external data option
    
    Add option to not encode resource data into the C source file
    in order to embed the data using `ld -b binary`. This improves compilation
    times, but can only be done on Linux or other platforms with a
    supporting linker.
    
    (Rebased by Philip Withnall, fixing minor rebase conflicts.)
    
    Fixes #1489

 docs/reference/gio/glib-compile-resources.xml | 10 ++++
 gio/glib-compile-resources.c                  | 71 ++++++++++++++++-----------
 gio/tests/Makefile.am                         | 15 +++++-
 gio/tests/meson.build                         | 67 ++++++++++++++++++++++---
 gio/tests/resources.c                         | 38 ++++++++++++++
 gio/tests/test5.gresource.xml                 |  6 +++
 6 files changed, 171 insertions(+), 36 deletions(-)
---
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 <option>--internal</option> does.
 </para></listitem>
 </varlistentry>
 
+<varlistentry>
+<term><option>--external-data</option></term>
+<listitem><para>
+By default code generated by <option>--generate-source</option> embeds the
+resource data as a string literal. When <option>--external-data</option>
+is given, the data is only declared in the generated C file, and the data
+has to be linked externally.
+</para></listitem>
+</varlistentry>
+
 <varlistentry>
 <term><option>--dependency-file=<replaceable>FILE</replaceable></option></term>
 <listitem><para>
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);
+
+          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");
+            }
 
-      g_fprintf (file, "} };\n");
+          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);
+          /* 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);
 
-      for (i = 0; i < data_size; i++) {
-       g_fprintf (file, "\\%3.3o", (int)data[i]);
-       if (i % 16 == 15)
-         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  \"");
+            }
 
-      g_fprintf (file, "\" };\n");
-      g_fprintf (file, "#endif /* !_MSC_VER */\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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/binary_linked">
+    <file>test1.txt</file>
+  </gresource>
+</gresources>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]