new tool to test gcc4/5 ABI
authorRobin Gareus <robin@gareus.org>
Sat, 26 Sep 2015 16:23:19 +0000 (18:23 +0200)
committerRobin Gareus <robin@gareus.org>
Sat, 26 Sep 2015 17:03:22 +0000 (19:03 +0200)
tools/gccabicheck/Makefile [new file with mode: 0644]
tools/gccabicheck/README [new file with mode: 0644]
tools/gccabicheck/abicheck.c [new file with mode: 0644]
tools/gccabicheck/wscript [new file with mode: 0644]
wscript

diff --git a/tools/gccabicheck/Makefile b/tools/gccabicheck/Makefile
new file mode 100644 (file)
index 0000000..2949e46
--- /dev/null
@@ -0,0 +1,19 @@
+CFLAGS = -Wall
+LOADLIBES = -ldl
+
+gcc-glibmm-abi-check:
+       $(CC) $(CPPFLAGS) $(CFLAGS) \
+               -o gcc-glibmm-abi-check \
+               abicheck.c \
+               $(LDFLAGS) $(LOADLIBES)
+
+check: gcc-glibmm-abi-check
+       ./gcc-glibmm-abi-check
+
+gcc-glibmm-abi-check.1: gcc-glibmm-abi-check
+       help2man -N \
+               -n 'glib gcc4/5 C++11 ABI compatibility test' \
+               -o gcc-glibmm-abi-check.1 \
+               ./gcc-glibmm-abi-check
+
+.PHONY: check
diff --git a/tools/gccabicheck/README b/tools/gccabicheck/README
new file mode 100644 (file)
index 0000000..f04da10
--- /dev/null
@@ -0,0 +1,34 @@
+g++5 ABI test tool
+==================
+
+This is a simple tool to test a system for g++5's glibmm at runtime.
+
+GCC5.1 introduced a new ABI for the C++ standard library.
+The old 3.4 .. 5.0 ABI is not compatible. By default gcc provides a
+dual ABI, so testing libstc++ itself is not sufficient.
+
+
+Some GNU/Linux distributions systems switched to the new ABI already
+and compile *plugins* with the new gcc.
+
+If a plugin uses a c++ library that is also shipped with ardour-bundles,
+the ABI of that library must match. Currently known cases: gtkmm, glibmm.
+
+e.g. Ingen or eq10q provided by a distro compiled with gcc5 will not
+load in Ardour from ardour.org compiled with gcc4 because ardour
+ships an incompatible gtkmm, glibmm, cairomm, ...
+
+Likewise Ardour gcc5-compiled binaries will fail to load plugins that
+are compiled with gcc4.
+
+This simiple tool `gcc-glibmm-abi-check` checks for gcc4/gcc5 specific
+symbols in libglibmm (a common denominator C++ lib), it is intended
+to be run when deploying ardour binaries.
+
+
+References
+----------
+
+https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
+https://wiki.debian.org/GCC5
+https://mail.gnome.org/archives/gtkmm-list/2015-June/thread.html
diff --git a/tools/gccabicheck/abicheck.c b/tools/gccabicheck/abicheck.c
new file mode 100644 (file)
index 0000000..fcff80e
--- /dev/null
@@ -0,0 +1,166 @@
+// gcc -Wall -o gcc-glibmm-abi-check abicheck.c -ldl
+// help2man -N -n 'glib gcc4/5 C++11 ABI compatibility test' -o gcc-glibmm-abi-check.1 ./gcc-glibmm-abi-check
+#include <stdio.h>
+#include <dlfcn.h>
+#include <getopt.h>
+
+#ifndef VERSION
+#define VERSION "0.1"
+#endif
+
+static void print_usage (void) {
+       printf ("gcc-glibmm-abi-check - gcc4/5 C++11 ABI compatibility test\n\n");
+
+       printf ("Usage: gcc-glibmm-abi-check [ OPTIONS ]\n\n");
+       printf (
+                       "This tool checks for C++ specific symbols in libglimm which are different in\n"
+                       "the gcc4 and gcc5/c++11 ABI in order to determine system-wide use of gcc5.\n"
+                       // TODO document error codes,...
+                       );
+
+       printf ("\nOptions:\n"
+                       " -f, --fail                fail if system cannot be determined.\n"
+                       " -h, --help                Display this help and exit.\n"
+                       " -4, --gcc4                Test succeeds if gcc4 ABI is found.\n"
+                       " -5, --gcc5                Test succeeds if gcc5 ABI is found.\n"
+                       " -g <soname>, --glibmm <soname>\n"
+                       "                           Specify alternative file for libglibmm-2.4.so\n"
+                       " -v, --verbose             Print information.\n"
+                       " -V, --version             Print version information and exit.\n"
+                       );
+}
+
+static void print_version (void) {
+       printf ("gcc-glibmm-abi-check version %s\n\n", VERSION);
+       printf (
+                       "Copyright (C) GPL 2015 Robin Gareus <robin@gareus.org>\n"
+                       "This is free software; see the source for copying conditions.  There is NO\n"
+                       "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+}
+
+
+int main (int argc, char **argv) {
+       int expect = 0;
+       int error_fail = 0;
+       int verbose = 0;
+
+       char *glibmm = "libglibmm-2.4.so";
+
+       const struct option long_options[] = {
+               { "help",       no_argument,       0, 'h' },
+               { "gcc4",       no_argument,       0, '4' },
+               { "gcc5",       no_argument,       0, '5' },
+               { "glibmm",     required_argument, 0, 'g' },
+               { "version",    no_argument,       0, 'V' },
+       };
+
+       const char *optstring = "fh45g:vV";
+
+       int c;
+       while ((c = getopt_long (argc, argv, optstring, long_options, NULL)) != -1) {
+               switch (c) {
+                       case 'f':
+                               error_fail = 1;
+                               break;
+                       case 'h':
+                               print_usage ();
+                               return 0;
+                               break;
+                       case '4':
+                               expect |= 1;
+                               break;
+                       case '5':
+                               expect |= 2;
+                               break;
+                       case 'g':
+                               glibmm = optarg;
+                               break;
+                       case 'v':
+                               verbose = 1;
+                               break;
+                       case 'V':
+                               print_version ();
+                               return 0;
+                               break;
+                       default:
+                               fprintf (stderr, "invalid argument.\n");
+                               print_usage ();
+                               return -1;
+                               break;
+               }
+       }
+
+       int gcc5 = 0;
+       int gcc4 = 0;
+
+       dlerror (); // reset error
+
+       void *h = dlopen (glibmm, RTLD_LAZY);
+       if (!h) {
+               if (verbose) {
+                       fprintf (stderr, "Cannot open '%s': %s.\n", glibmm, dlerror ());
+               }
+               return error_fail ? 3 : 0;
+       }
+
+       // Glib::ustring::ustring(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
+       if (dlsym (h, "_ZN4Glib7ustringC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE")) {
+               gcc5 |= 1;
+       }
+
+       // Glib::ustring::ustring(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
+       if (dlsym (h, "_ZN4Glib7ustringC1ERKSs")) {
+               gcc4 |= 1;
+       }
+
+
+       // Glib::Module::Module(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Glib::ModuleFlags)
+       if (dlsym (h, "_ZN4Glib6ModuleC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS_11ModuleFlagsE")) {
+               gcc5 |= 2;
+       }
+
+       // Glib::Module::Module(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Glib::ModuleFlags)
+       if (dlsym (h, "_ZN4Glib6ModuleC1ERKSsNS_11ModuleFlagsE")) {
+               gcc4 |= 2;
+       }
+
+
+       // Glib::ustring::operator=(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
+       if (dlsym (h, "_ZN4Glib7ustringaSERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE")) {
+               gcc5 |= 4;
+       }
+
+       // Glib::ustring::operator=(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
+       if (dlsym (h, "_ZN4Glib7ustringaSERKSs")) {
+               gcc4 |= 4;
+       }
+
+       dlclose (h);
+
+       if (7 != (gcc4 ^ gcc5)) {
+               if (verbose) {
+                       fprintf (stderr, "Inconsistent result: gcc4=%x gcc5=%x\n", gcc4, gcc5);
+               }
+       }
+       else if (gcc4 == 7) {
+               if (verbose) {
+                       printf ("System uses gcc4 c++ ABI\n");
+               }
+               if (expect != 0) {
+                       return (expect & 1) ? 0 : 1;
+               }
+       }
+       else if (gcc5 == 7) {
+               if (verbose) {
+                       printf ("System uses gcc5 c++11 ABI\n");
+               }
+               if (expect != 0) {
+                       return (expect & 2) ? 0 : 1;
+               }
+       }
+       else if (verbose) {
+               fprintf (stderr, "Incomplete result: gcc4=%x gcc5=%x\n", gcc4, gcc5);
+       }
+
+       return error_fail ? 2 : 0;
+}
diff --git a/tools/gccabicheck/wscript b/tools/gccabicheck/wscript
new file mode 100644 (file)
index 0000000..43eb705
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+from waflib.extras import autowaf as autowaf
+from waflib import Options
+import os
+
+# Mandatory variables
+top = '.'
+out = 'build'
+
+def options(opt):
+    autowaf.set_options(opt)
+
+def configure(conf):
+    conf.load('compiler_c')
+    autowaf.configure(conf)
+
+def build(bld):
+    obj = bld(features = 'c cprogram')
+    obj.source = [ 'abicheck.c' ]
+    obj.target = 'gcc-glibmm-abi-check'
+    obj.name = 'gcc-glibmm-abi-check'
+    obj.lib = 'dl'
diff --git a/wscript b/wscript
index 857f89ccf8776f381000bb6482a1a70c21df0628..a1124f42f67362ff66650e7948a7d62de4f1c5dd 100644 (file)
--- a/wscript
+++ b/wscript
@@ -1070,6 +1070,7 @@ int main () { int x = SFC_AUTO_DOWNGRADE_RF64; return 0; }
         sub_config_and_use(conf, 'libs/appleutility')
     elif Options.options.dist_target != 'mingw':
         sub_config_and_use(conf, 'tools/sanity_check')
+        sub_config_and_use(conf, 'tools/gccabicheck')
 
     sub_config_and_use(conf, 'libs/clearlooks-newer')
 
@@ -1185,6 +1186,7 @@ def build(bld):
         bld.recurse('libs/appleutility')
     elif bld.env['build_target'] != 'mingw':
         bld.recurse('tools/sanity_check')
+        bld.recurse('tools/gccabicheck')
 
     bld.recurse('libs/clearlooks-newer')