From a2dee162af41c80827ff60d87c08ea981b55b31b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 19 Mar 2013 15:02:31 +0200 Subject: Add support for installing plugin into default GCC plugin directory --- configure.ac | 59 +++++++++++++------------ m4/gcc-plugin.m4 | 125 +++++++++++++++++++++++++++++++++++++++++++++++----- odb/Makefile.am | 4 +- odb/odb.cxx | 131 +++++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 245 insertions(+), 74 deletions(-) diff --git a/configure.ac b/configure.ac index 320b060..35a0fa1 100644 --- a/configure.ac +++ b/configure.ac @@ -20,29 +20,37 @@ AC_CANONICAL_HOST AC_PROG_CXX AC_LANG(C++) +# Create the libtool executable so that we can use it in further tests. +# +LT_OUTPUT + +# Test for plugin support in GCC. +# +GCC_PLUGIN + # See if we are building static plugin. Static build should only be # used if you are building a custom version of GCC with the ODB # plugin linked-in statically. This is primarily useful on Windows # where GCC plugins are not (yet) supported due to dynamic loading -# limitations. +# limitations. In this case the headers normally come from the GCC +# build directly via CPPFLAGS. # -static_plugin="$enable_static" - -AS_IF([test x$static_plugin = xyes], +if test x$static_plugin = xyes; then AC_WARN([Building static plugin for direct linking into GCC executable!]) - AC_DEFINE([ODB_STATIC_PLUGIN], [1], [Building static plugin.])) + AC_DEFINE([ODB_STATIC_PLUGIN], [1], [Building static plugin.]) + plugindir='$(pkglibexecdir)' -# Check for plugin support in GCC unless we are building a static plugin. -# In the latter case the headers normally come from the GCC build directly -# via CPPFLAGS. +# Otherwise, see if we should install the plugin into the GCC plugin dir. # -AS_IF([test x$static_plugin = xno], GCC_PLUGIN) +elif test x$gcc_plugin_dir != xno; then + AC_DEFINE([ODB_GCC_PLUGIN_DIR], [1], [Plugin is in GCC plugin directory.]) + plugindir=$gcc_plugin_dir -# Unless we are building a static plugin, try to figure out a relative -# path from the driver (bindir) to the plugin (libexecdir). +# Otherwise, try to figure out a relative path from the driver (bindir) to +# the plugin (libexecdir). # -if test x$static_plugin = xno; then - # Get the expanded values for bindif and libexecdir. +elif test x$static_plugin = xno; then + # Get the expanded values for bindir and libexecdir. # if test x$exec_prefix = xNONE; then if test x$prefix = xNONE; then @@ -60,32 +68,35 @@ if test x$static_plugin = xno; then # Try to find a common prefix. # common=$e_bindir - odb_plugindir=$e_pkglibexecdir + rel_plugindir=$e_pkglibexecdir while test x$common != x/; do suffix=`echo "$e_pkglibexecdir" | sed "s?^$common/*??"` if test x$suffix != x$e_pkglibexecdir; then # Replace all the remaining directories in bindir with ".." # and append the suffix. - odb_plugindir=`echo "$e_bindir" | sed "s?^$common/*??"` - odb_plugindir=`echo "$odb_plugindir" | sed ['s?[^/][^/]*?..?g']` - if test x$odb_plugindir != x -a x$suffix != x; then - odb_plugindir="$odb_plugindir/$suffix" + rel_plugindir=`echo "$e_bindir" | sed "s?^$common/*??"` + rel_plugindir=`echo "$rel_plugindir" | sed ['s?[^/][^/]*?..?g']` + if test x$rel_plugindir != x -a x$suffix != x; then + rel_plugindir="$rel_plugindir/$suffix" else - odb_plugindir="$odb_plugindir$suffix" + rel_plugindir="$rel_plugindir$suffix" fi break fi common=`AS_DIRNAME(["$common"])` done - AC_DEFINE_UNQUOTED([ODB_PLUGIN_PATH], ["$odb_plugindir"], [Plugin path.]) + AC_DEFINE_UNQUOTED([ODB_PLUGIN_PATH], ["$rel_plugindir"], [Plugin path.]) + plugindir='$(pkglibexecdir)' fi +AC_SUBST([plugindir]) + # G++ name. # AC_ARG_WITH( [gxx-name], - [AC_HELP_STRING([--with-gxx-name=NAME], [g++ binary to embed in the driver])], + [AC_HELP_STRING([--with-gxx-name=NAME], [g++ executable name to embed in the ODB compiler driver])], [case $withval in no) gxx_name= @@ -125,16 +136,10 @@ AS_IF( [test "x$options_file" != x], [AC_DEFINE_UNQUOTED([ODB_DEFAULT_OPTIONS_FILE], ["$options_file"], [default options file path.])]) -# Create the libtool executable so that we can use it in further tests. -# -LT_OUTPUT - - # Check for libcutl. # LIBCUTL([],[AC_MSG_ERROR([libcutl is not found; consider using --with-libcutl=DIR])]) - # Check if we should disable rpath. # DISABLE_RPATH diff --git a/m4/gcc-plugin.m4 b/m4/gcc-plugin.m4 index 27453a2..27ce15d 100644 --- a/m4/gcc-plugin.m4 +++ b/m4/gcc-plugin.m4 @@ -5,23 +5,124 @@ dnl dnl GCC_PLUGIN dnl AC_DEFUN([GCC_PLUGIN], [ -gcc_plugin_support=no +static_plugin=$enable_static -if test x"$GXX" != xyes; then - AC_MSG_ERROR([$CXX is not a GNU C++ compiler]) +AC_ARG_WITH( + [gcc-plugin-dir], + [AC_HELP_STRING([--with-gcc-plugin-dir=DIR], [install ODB plugin into the GCC plugin directory])], + [gcc_plugin_dir=$withval], + [gcc_plugin_dir=test]) + +if test x"$static_plugin" = xyes; then + gcc_plugin_dir=no +else + if test x"$cross_compiling" = xyes; then + AC_MSG_CHECKING([whether to install into default GCC plugin dir]) + case $gcc_plugin_dir in + yes) + AC_MSG_ERROR([GCC plugin directory must be specified explicitly when cross-compiling]) + ;; + test) + # We cannot detect the plugin directory since there is no way to + # run host GCC. So assume no. + # + gcc_plugin_dir=no + ;; + no) + ;; + *) + # Add the include/ subdirectory of the plugin dir to CPPFLAGS since + # the plugin headers are normally installed there. + # + CPPFLAGS="$CPPFLAGS -I$gcc_plugin_dir/include" + ;; + esac + else + if test x"$GXX" != xyes; then + AC_MSG_ERROR([$CXX is not a GNU C++ compiler]) + fi + + AC_MSG_CHECKING([whether $CXX supports plugins]) + dir=`$CXX -print-file-name=plugin 2>/dev/null` + + if test x"$dir" = xplugin; then + AC_MSG_RESULT([no]) + AC_MSG_ERROR([$CXX does not support plugins; reconfigure GCC with --enable-plugin]) + else + AC_MSG_RESULT([yes]) + fi + + CPPFLAGS="$CPPFLAGS -I$dir/include" + + AC_MSG_CHECKING([whether to install ODB plugin into default GCC plugin directory]) + case $gcc_plugin_dir in + yes) + gcc_plugin_dir=$dir + ;; + test) + # Only install into the GCC plugin dir if both GCC and ODB are + # installed into the same prefix. Testing whether $libdir or + # $libexecdir is a prefix of the GCC plugin dir is a good + # approximation. + # + + # Get the expanded values for libdir and libexecdir. + # + if test x$exec_prefix = xNONE; then + if test x$prefix = xNONE; then + e_exec_prefix=$ac_default_prefix + else + e_exec_prefix=$prefix + fi + else + e_exec_prefix=$exec_prefix + fi + + e_libdir=`echo "$libdir" | sed "s?^\\\${exec_prefix}?$e_exec_prefix?"` + e_libexecdir=`echo "$libexecdir" | sed "s?^\\\${exec_prefix}?$e_exec_prefix?"` + + # See if either one of them is a prefix of the plugin dir. + # + ld_suffix=`echo "$dir" | sed "s?^$e_libdir/*??"` + led_suffix=`echo "$dir" | sed "s?^$e_libexecdir/*??"` + + if test x$ld_suffix != x$dir -o x$led_suffix != x$dir; then + gcc_plugin_dir=$dir + else + gcc_plugin_dir=no + fi + ;; + *) + ;; + esac + fi + + if test x"$gcc_plugin_dir" != xno; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi fi -AC_MSG_CHECKING([whether $CXX supports plugins]) +AC_MSG_CHECKING([for GCC plugin headers]) -gcc_plugin_base=`$CXX -print-file-name=plugin 2>/dev/null` +CXX_LIBTOOL_LINK_IFELSE([ +AC_LANG_SOURCE([ +#include -if test x"$gcc_plugin_base" = xplugin; then - AC_MSG_RESULT([no]) - AC_MSG_ERROR([$CXX does not support plugins; reconfigure GCC with --enable-plugin or install plugin headers]) -else +#ifndef BUILDING_GCC_MAJOR +# error no BUILDING_GCC_MAJOR in bversion.h +#endif + +int main () {} +])], +[gcc_plugin_headers=yes], +[gcc_plugin_headers=no]) + +if test x"$gcc_plugin_headers" = xyes; then AC_MSG_RESULT([yes]) - gcc_plugin_support=yes +else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([GCC plugin headers not found; consider installing GCC plugin development package]) fi - -CPPFLAGS="$CPPFLAGS -I$gcc_plugin_base/include" ])dnl diff --git a/odb/Makefile.am b/odb/Makefile.am index bc2fc76..f9d9703 100644 --- a/odb/Makefile.am +++ b/odb/Makefile.am @@ -2,7 +2,7 @@ # copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC # license : GNU GPL v3; see accompanying LICENSE file -plugindir = $(pkglibexecdir) +plugindir = @plugindir@ bin_PROGRAMS = odb plugin_LTLIBRARIES = odb.la @@ -19,7 +19,7 @@ odb_la_LDFLAGS = -module -shrext .so -avoid-version # Remove the .la file from the final install. # install-data-hook: - rm -f '$(DESTDIR)$(pkglibexecdir)/odb.la' + rm -f '$(DESTDIR)$(plugindir)/odb.la' # Driver. # diff --git a/odb/odb.cxx b/odb/odb.cxx index 9491252..74ef5a4 100644 --- a/odb/odb.cxx +++ b/odb/odb.cxx @@ -70,7 +70,7 @@ driver_path (path const& driver); #ifndef ODB_STATIC_PLUGIN static path -plugin_path (path const& driver); +plugin_path (path const& driver, string const& gxx); #endif // @@ -140,25 +140,6 @@ main (int argc, char* argv[]) try { - // Find the plugin. It should be in the same directory as the - // driver. - // -#ifndef ODB_STATIC_PLUGIN - path plugin (plugin_path (path (argv[0]))); -#else - // Use a dummy name if the plugin is linked into the compiler. - // - path plugin ("odb"); -#endif - - if (plugin.empty ()) - { - e << argv[0] << ": error: unable to locate ODB GCC plugin" << endl; - e << argv[0] << ": info: make sure '" << argv[0] << ".so' is in " - << "the same directory as '" << argv[0] << "'" << endl; - return 1; - } - strings args, plugin_args; bool v (false); @@ -236,7 +217,7 @@ main (int argc, char* argv[]) args.push_back ("-S"); args.push_back ("-Wunknown-pragmas"); args.push_back ("-Wno-deprecated"); - args.push_back ("-fplugin=" + plugin.string ()); + args.push_back (""); // Reserve space for -fplugin=path. // Parse the default options file if we have one. // @@ -522,6 +503,23 @@ main (int argc, char* argv[]) // args.insert (args.end (), def_inc_dirs.begin (), def_inc_dirs.end ()); + // Find the plugin. + // + { +#ifndef ODB_STATIC_PLUGIN + path plugin (plugin_path (path (argv[0]), args[0])); +#else + // Use a dummy name if the plugin is linked into the compiler. + // + path plugin ("odb"); +#endif + + if (plugin.empty ()) + return 1; // Diagnostics has already been issued. + + args[7] = "-fplugin=" + plugin.string (); + } + // Parse plugin options. We have to do it twice to get the target // database which is needed while loading profiles. // @@ -1433,7 +1431,12 @@ driver_path (path const& drv) #ifndef ODB_STATIC_PLUGIN static path -plugin_path (path const& drv) +plugin_path (path const& drv, +#ifdef ODB_GCC_PLUGIN_DIR + string const& gxx) +#else + string const&) +#endif { // Figure out the plugin base name which is just the driver name. // If the driver name starts with 'lt-', then we are running through @@ -1448,7 +1451,10 @@ plugin_path (path const& drv) path dp (driver_path (drv)); if (dp.empty ()) - return path (); // Fail. + { + cerr << drv << ": error: unable to resolve ODB driver path" << endl; + return path (); + } dp = dp.directory (); struct stat info; @@ -1465,32 +1471,91 @@ plugin_path (path const& drv) return pp; } -#ifdef ODB_PLUGIN_PATH +#ifdef ODB_GCC_PLUGIN_DIR + // Plugin should be installed into the GCC default plugin directory. + // Ideally, in this situation, we would simply pass the plugin name and + // let GCC append the correct directory. Unfortunately, this mechanism + // was only added in GCC 4.6 so in order to support 4.5 we will have to + // emulate it ourselves. + // + if (!lt) + { + // First get the default GCC plugin directory. + // + path d; + vector exec_args; + exec_args.push_back (gxx.c_str ()); + exec_args.push_back ("-print-file-name=plugin"); + exec_args.push_back (0); + + process_info pi ( + start_process ( + &exec_args[0], drv.string ().c_str (), false, true)); + close (pi.out_fd); + + // Read the path from stdout. + // + { + __gnu_cxx::stdio_filebuf fb (pi.in_ofd, ios_base::in); + istream is (&fb); + string line; + getline (is, line); + d = path (line); + } + + if (!wait_process (pi, drv.string ().c_str ())) + return path (); // Assume GCC issued some diagnostics. + + if (d.string () == "plugin") + { + cerr << drv << ": error: unable to obtain GCC plugin directory" << endl; + return path (); + } + + // See if the plugin is there. + // + pp = d / path (b + ".so"); + if (stat (pp.string ().c_str (), &info) != 0) + { + cerr << drv << ": error: no ODB plugin in GCC plugin directory '" << + d << "'" << endl; + return path (); + } + + return pp; + } +#elif defined (ODB_PLUGIN_PATH) // If we were given a plugin path, use that unless we are running // via libtool. // if (!lt) { string rp (ODB_PLUGIN_PATH); - pp = dp; if (!rp.empty ()) - pp /= path (rp); - pp /= path (b + ".so"); + dp /= path (rp); - if (stat (pp.string ().c_str (), &info) == 0) - return pp; + pp = dp / path (b + ".so"); + + if (stat (pp.string ().c_str (), &info) != 0) + { + cerr << drv << ": error: no ODB plugin in '" << dp << "'" << endl; + return path (); + } - return path (); // Fail. + return pp; } #endif // Try .so in the current directory. // pp = dp / path (b + ".so"); - if (stat (pp.string ().c_str (), &info) == 0) - return pp; + if (stat (pp.string ().c_str (), &info) != 0) + { + cerr << drv << ": error: unable to locate ODB plugin" << endl; + return path (); + } - return path (); + return pp; } #endif -- cgit v1.1