From ba6e274efa8ec04ffa26cb74a4a9879294720bdf Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sat, 26 Sep 2015 18:23:19 +0200 Subject: [PATCH] new tool to test gcc4/5 ABI --- tools/gccabicheck/Makefile | 19 ++++ tools/gccabicheck/README | 34 +++++++ tools/gccabicheck/abicheck.c | 166 +++++++++++++++++++++++++++++++++++ tools/gccabicheck/wscript | 22 +++++ wscript | 2 + 5 files changed, 243 insertions(+) create mode 100644 tools/gccabicheck/Makefile create mode 100644 tools/gccabicheck/README create mode 100644 tools/gccabicheck/abicheck.c create mode 100644 tools/gccabicheck/wscript diff --git a/tools/gccabicheck/Makefile b/tools/gccabicheck/Makefile new file mode 100644 index 0000000000..2949e46633 --- /dev/null +++ b/tools/gccabicheck/Makefile @@ -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 index 0000000000..f04da108d3 --- /dev/null +++ b/tools/gccabicheck/README @@ -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 index 0000000000..fcff80e611 --- /dev/null +++ b/tools/gccabicheck/abicheck.c @@ -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 +#include +#include + +#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 , --glibmm \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 \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, std::allocator > const&) + if (dlsym (h, "_ZN4Glib7ustringC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE")) { + gcc5 |= 1; + } + + // Glib::ustring::ustring(std::basic_string, std::allocator > const&) + if (dlsym (h, "_ZN4Glib7ustringC1ERKSs")) { + gcc4 |= 1; + } + + + // Glib::Module::Module(std::__cxx11::basic_string, std::allocator > const&, Glib::ModuleFlags) + if (dlsym (h, "_ZN4Glib6ModuleC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS_11ModuleFlagsE")) { + gcc5 |= 2; + } + + // Glib::Module::Module(std::basic_string, std::allocator > const&, Glib::ModuleFlags) + if (dlsym (h, "_ZN4Glib6ModuleC1ERKSsNS_11ModuleFlagsE")) { + gcc4 |= 2; + } + + + // Glib::ustring::operator=(std::__cxx11::basic_string, std::allocator > const&) + if (dlsym (h, "_ZN4Glib7ustringaSERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE")) { + gcc5 |= 4; + } + + // Glib::ustring::operator=(std::basic_string, std::allocator > 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 index 0000000000..43eb705bd5 --- /dev/null +++ b/tools/gccabicheck/wscript @@ -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 857f89ccf8..a1124f42f6 100644 --- 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')