aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-11-26 13:00:48 +0000
committerJonathan Yong <10walls@gmail.com>2017-11-26 13:00:48 +0000
commit114f01457449db7c02ad6920ee73a5fc0e124387 (patch)
treec02088e446e880dcebb2359db9e0c6d8c5681dd2
parentcec13eb618653be8ffd98629d5b11388a9cd569c (diff)
Plugin support on Windows/MinGW
config/ChangeLog: 2017-11-14 Boris Kolpackov <boris@codesynthesis.com> * gcc-plugin.m4: Add support for MinGW. gcc/ChangeLog: 2017-11-14 Boris Kolpackov <boris@codesynthesis.com> * plugin.c (add_new_plugin): Use platform-specific library extensions. (try_init_one_plugin): Alternative implementation for MinGW. * Makefile.in (plugin_implib): New. (gengtype-lex.c): Fix broken AIX workaround. * configure: Regenerate. * doc/plugins.texi: Document support for MinGW. gcc/c/ChangeLog: 2017-11-14 Boris Kolpackov <boris@codesynthesis.com> * Make-lang.in (c.install-plugin): Install backend import library. gcc/cp/ChangeLog: 2017-11-14 Boris Kolpackov <boris@codesynthesis.com> * Make-lang.in (c++.install-plugin): Install backend import library. libcc1/ChangeLog: 2017-11-14 Boris Kolpackov <boris@codesynthesis.com> * configure: Regenerate. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@255154 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--config/ChangeLog4
-rw-r--r--config/gcc-plugin.m415
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/Makefile.in14
-rw-r--r--gcc/c/ChangeLog4
-rw-r--r--gcc/c/Make-lang.in9
-rwxr-xr-xgcc/configure15
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/Make-lang.in5
-rw-r--r--gcc/doc/plugins.texi55
-rw-r--r--gcc/plugin.c120
-rw-r--r--libcc1/ChangeLog4
-rwxr-xr-xlibcc1/configure15
13 files changed, 253 insertions, 20 deletions
diff --git a/config/ChangeLog b/config/ChangeLog
index 2bb5244caa4..a44722ed528 100644
--- a/config/ChangeLog
+++ b/config/ChangeLog
@@ -1,3 +1,7 @@
+2017-11-14 Boris Kolpackov <boris@codesynthesis.com>
+
+ * gcc-plugin.m4: Add support for MinGW.
+
2017-11-17 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
* cet.m4: New file.
diff --git a/config/gcc-plugin.m4 b/config/gcc-plugin.m4
index dd06a58cd13..38b2ae6e12e 100644
--- a/config/gcc-plugin.m4
+++ b/config/gcc-plugin.m4
@@ -19,8 +19,21 @@ AC_DEFUN([GCC_ENABLE_PLUGINS],
enable_plugin=yes; default_plugin=yes)
pluginlibs=
+ plugin_check=yes
case "${host}" in
+ *-*-mingw*)
+ # Since plugin support under MinGW is not as straightforward as on
+ # other platforms (e.g., we have to link import library, etc), we
+ # only enable it if explicitly requested.
+ if test x"$default_plugin" = x"yes"; then
+ enable_plugin=no
+ elif test x"$enable_plugin" = x"yes"; then
+ # Use make's target variable to derive import library name.
+ pluginlibs='-Wl,--export-all-symbols -Wl,--out-implib=[$]@.a'
+ plugin_check=no
+ fi
+ ;;
*-*-darwin*)
if test x$build = x$host; then
export_sym_check="nm${exeext} -g"
@@ -41,7 +54,7 @@ AC_DEFUN([GCC_ENABLE_PLUGINS],
;;
esac
- if test x"$enable_plugin" = x"yes"; then
+ if test x"$enable_plugin" = x"yes" -a x"$plugin_check" = x"yes"; then
AC_MSG_CHECKING([for exported symbols])
if test "x$export_sym_check" != x; then
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3445e3e08ee..e52effababa 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2017-11-14 Boris Kolpackov <boris@codesynthesis.com>
+
+ * plugin.c (add_new_plugin): Use platform-specific library extensions.
+ (try_init_one_plugin): Alternative implementation for MinGW.
+ * Makefile.in (plugin_implib): New.
+ (gengtype-lex.c): Fix broken AIX workaround.
+ * configure: Regenerate.
+ * doc/plugins.texi: Document support for MinGW.
+
2017-11-25 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/81553
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index f2a897c5962..c428eaab023 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -57,6 +57,7 @@ MAKEOVERRIDES =
build=@build@
host=@host@
host_noncanonical=@host_noncanonical@
+host_os=@host_os@
target=@target@
target_noncanonical:=@target_noncanonical@
@@ -393,6 +394,11 @@ PLUGINLIBS = @pluginlibs@
enable_plugin = @enable_plugin@
+# On MinGW plugin installation involves installing import libraries.
+ifeq ($(enable_plugin),yes)
+ plugin_implib := $(if $(strip $(filter mingw%,$(host_os))),yes,no)
+endif
+
enable_host_shared = @enable_host_shared@
enable_as_accelerator = @enable_as_accelerator@
@@ -2828,11 +2834,15 @@ $(genprog:%=build/gen%$(build_exeext)): build/gen%$(build_exeext): build/gen%.o
$(filter-out $(BUILD_LIBDEPS), $^) $(BUILD_LIBS)
# Generated source files for gengtype. Prepend inclusion of
-# bconfig.h because AIX requires _LARGE_FILES to be defined before
+# config.h/bconfig.h because AIX requires _LARGE_FILES to be defined before
# any system header is included.
gengtype-lex.c : gengtype-lex.l
-$(FLEX) $(FLEXFLAGS) -o$@ $< && { \
- echo '#include "bconfig.h"' > $@.tmp; \
+ echo '#ifdef HOST_GENERATOR_FILE' > $@.tmp; \
+ echo '#include "config.h"' >> $@.tmp; \
+ echo '#else' >> $@.tmp; \
+ echo '#include "bconfig.h"' >> $@.tmp; \
+ echo '#endif' >> $@.tmp; \
cat $@ >> $@.tmp; \
mv $@.tmp $@; \
}
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 1d698508131..087a1e7cfaf 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,7 @@
+2017-11-14 Boris Kolpackov <boris@codesynthesis.com>
+
+ * Make-lang.in (c.install-plugin): Install backend import library.
+
2017-11-23 Jakub Jelinek <jakub@redhat.com>
* c-parser.c (c_parser_omp_declare_simd): Reject declare simd in
diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in
index cfd8cd2b169..b194f227646 100644
--- a/gcc/c/Make-lang.in
+++ b/gcc/c/Make-lang.in
@@ -125,7 +125,14 @@ check-c : check-gcc
c.install-common:
c.install-man:
-c.install-plugin:
+
+c.install-plugin: installdirs
+# Install import library.
+ifeq ($(plugin_implib),yes)
+ $(mkinstalldirs) $(DESTDIR)$(plugin_resourcesdir)
+ $(INSTALL_DATA) cc1$(exeext).a $(DESTDIR)/$(plugin_resourcesdir)/cc1$(exeext).a
+endif
+
c.uninstall:
#
diff --git a/gcc/configure b/gcc/configure
index d4461e2fdd2..39eb3c82930 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -29619,8 +29619,21 @@ fi
pluginlibs=
+ plugin_check=yes
case "${host}" in
+ *-*-mingw*)
+ # Since plugin support under MinGW is not as straightforward as on
+ # other platforms (e.g., we have to link import library, etc), we
+ # only enable it if explicitly requested.
+ if test x"$default_plugin" = x"yes"; then
+ enable_plugin=no
+ elif test x"$enable_plugin" = x"yes"; then
+ # Use make's target variable to derive import library name.
+ pluginlibs='-Wl,--export-all-symbols -Wl,--out-implib=$@.a'
+ plugin_check=no
+ fi
+ ;;
*-*-darwin*)
if test x$build = x$host; then
export_sym_check="nm${exeext} -g"
@@ -29641,7 +29654,7 @@ fi
;;
esac
- if test x"$enable_plugin" = x"yes"; then
+ if test x"$enable_plugin" = x"yes" -a x"$plugin_check" = x"yes"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for exported symbols" >&5
$as_echo_n "checking for exported symbols... " >&6; }
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e93964178eb..854df5afe91 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,7 @@
+2017-11-14 Boris Kolpackov <boris@codesynthesis.com>
+
+ * Make-lang.in (c++.install-plugin): Install backend import library.
+
2017-11-23 Jakub Jelinek <jakub@redhat.com>
* parser.c (cp_parser_omp_declare): Change return type to bool from
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index c852f6a38b4..7af4a4cb0b8 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -238,6 +238,11 @@ c++.install-plugin: installdirs
$(mkinstalldirs) $(DESTDIR)$$dir; \
$(INSTALL_DATA) $$path $(DESTDIR)$$dest; \
done
+# Install import library.
+ifeq ($(plugin_implib),yes)
+ $(mkinstalldirs) $(DESTDIR)$(plugin_resourcesdir)
+ $(INSTALL_DATA) cc1plus$(exeext).a $(DESTDIR)/$(plugin_resourcesdir)/cc1plus$(exeext).a
+endif
c++.uninstall:
-rm -rf $(DESTDIR)$(bindir)/$(CXX_INSTALL_NAME)$(exeext)
diff --git a/gcc/doc/plugins.texi b/gcc/doc/plugins.texi
index 6fc7b9ae9a2..dc3fa212881 100644
--- a/gcc/doc/plugins.texi
+++ b/gcc/doc/plugins.texi
@@ -34,14 +34,17 @@ can be quite useful.
@section Loading Plugins
Plugins are supported on platforms that support @option{-ldl
--rdynamic}. They are loaded by the compiler using @code{dlopen}
-and invoked at pre-determined locations in the compilation
-process.
+-rdynamic} as well as Windows/MinGW. They are loaded by the compiler
+using @code{dlopen} or equivalent and invoked at pre-determined
+locations in the compilation process.
Plugins are loaded with
-@option{-fplugin=/path/to/@var{name}.so} @option{-fplugin-arg-@var{name}-@var{key1}[=@var{value1}]}
+@option{-fplugin=/path/to/@var{name}.@var{ext}} @option{-fplugin-arg-@var{name}-@var{key1}[=@var{value1}]}
+Where @var{name} is the plugin name and @var{ext} is the platform-specific
+dynamic library extension. It should be @code{dll} on Windows/MinGW,
+@code{dylib} on Darwin/Mac OS X, and @code{so} on all other platforms.
The plugin arguments are parsed by GCC and passed to respective
plugins as key-value pairs. Multiple plugins can be invoked by
specifying multiple @option{-fplugin} arguments.
@@ -49,7 +52,7 @@ specifying multiple @option{-fplugin} arguments.
A plugin can be simply given by its short name (no dots or
slashes). When simply passing @option{-fplugin=@var{name}}, the plugin is
loaded from the @file{plugin} directory, so @option{-fplugin=@var{name}} is
-the same as @option{-fplugin=`gcc -print-file-name=plugin`/@var{name}.so},
+the same as @option{-fplugin=`gcc -print-file-name=plugin`/@var{name}.@var{ext}},
using backquote shell syntax to query the @file{plugin} directory.
@node Plugin API
@@ -508,6 +511,48 @@ A single source file plugin may be built with @code{g++ -I`gcc
plugin.so}, using backquote shell syntax to query the @file{plugin}
directory.
+Plugin support on Windows/MinGW has a number of limitations and
+additional requirements. When building a plugin on Windows we have to
+link an import library for the corresponding backend executable, for
+example, @file{cc1.exe}, @file{cc1plus.exe}, etc., in order to gain
+access to the symbols provided by GCC. This means that on Windows a
+plugin is language-specific, for example, for C, C++, etc. If you wish
+to use your plugin with multiple languages, then you will need to
+build multiple plugin libraries and either instruct your users on how
+to load the correct version or provide a compiler wrapper that does
+this automatically.
+
+Additionally, on Windows the plugin library has to export the
+@code{plugin_is_GPL_compatible} and @code{plugin_init} symbols. If you
+do not wish to modify the source code of your plugin, then you can use
+the @option{-Wl,--export-all-symbols} option or provide a suitable DEF
+file. Alternatively, you can export just these two symbols by decorating
+them with @code{__declspec(dllexport)}, for example:
+
+@smallexample
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int plugin_is_GPL_compatible;
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int plugin_init (plugin_name_args *, plugin_gcc_version *)
+@end smallexample
+
+The import libraries are installed into the @code{plugin} directory
+and their names are derived by appending the @code{.a} extension to
+the backend executable names, for example, @file{cc1.exe.a},
+@file{cc1plus.exe.a}, etc. The following command line shows how to
+build the single source file plugin on Windows to be used with the C++
+compiler:
+
+@smallexample
+g++ -I`gcc -print-file-name=plugin`/include -shared -Wl,--export-all-symbols \
+-o plugin.dll plugin.c `gcc -print-file-name=plugin`/cc1plus.exe.a
+@end smallexample
+
When a plugin needs to use @command{gengtype}, be sure that both
@file{gengtype} and @file{gtype.state} have the same version as the
GCC for which the plugin is built.
diff --git a/gcc/plugin.c b/gcc/plugin.c
index 9892748cd15..db18e642680 100644
--- a/gcc/plugin.c
+++ b/gcc/plugin.c
@@ -34,6 +34,16 @@ along with GCC; see the file COPYING3. If not see
#include "plugin-version.h"
#endif
+#ifdef __MINGW32__
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+#endif
+
#define GCC_PLUGIN_STRINGIFY0(X) #X
#define GCC_PLUGIN_STRINGIFY1(X) GCC_PLUGIN_STRINGIFY0 (X)
@@ -144,7 +154,7 @@ get_plugin_base_name (const char *full_name)
/* First get the base name part of the full-path name, i.e. NAME.so. */
char *base_name = xstrdup (lbasename (full_name));
- /* Then get rid of '.so' part of the name. */
+ /* Then get rid of the extension in the name, e.g., .so. */
strip_off_ending (base_name, strlen (base_name));
return base_name;
@@ -175,12 +185,27 @@ add_new_plugin (const char* plugin_name)
if (name_is_short)
{
base_name = CONST_CAST (char*, plugin_name);
- /* FIXME: the ".so" suffix is currently builtin, since plugins
- only work on ELF host systems like e.g. Linux or Solaris.
- When plugins shall be available on non ELF systems such as
- Windows or MacOS, this code has to be greatly improved. */
+
+#if defined(__MINGW32__)
+ static const char plugin_ext[] = ".dll";
+#elif defined(__APPLE__)
+ /* Mac OS has two types of libraries: dynamic libraries (.dylib) and
+ plugins (.bundle). Both can be used with dlopen()/dlsym() but the
+ former cannot be linked at build time (i.e., with the -lfoo linker
+ option). A GCC plugin is therefore probably a Mac OS plugin but their
+ use seems to be quite rare and the .bundle extension is more of a
+ recommendation rather than the rule. This raises the questions of how
+ well they are supported by tools (e.g., libtool). So to avoid
+ complications let's use the .dylib extension for now. In the future,
+ if this proves to be an issue, we can always check for both
+ extensions. */
+ static const char plugin_ext[] = ".dylib";
+#else
+ static const char plugin_ext[] = ".so";
+#endif
+
plugin_name = concat (default_plugin_dir_name (), "/",
- plugin_name, ".so", NULL);
+ plugin_name, plugin_ext, NULL);
if (access (plugin_name, R_OK))
fatal_error
(input_location,
@@ -573,6 +598,85 @@ invoke_plugin_callbacks_full (int event, void *gcc_data)
}
#ifdef ENABLE_PLUGIN
+
+/* Try to initialize PLUGIN. Return true if successful. */
+
+#ifdef __MINGW32__
+
+// Return a message string for last error or NULL if unknown. Must be freed
+// with LocalFree().
+static inline char *
+win32_error_msg ()
+{
+ char *msg;
+ return FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ 0,
+ GetLastError (),
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (char*)&msg,
+ 0,
+ 0)
+ ? msg
+ : NULL;
+}
+
+static bool
+try_init_one_plugin (struct plugin_name_args *plugin)
+{
+ HMODULE dl_handle;
+ plugin_init_func plugin_init;
+
+ dl_handle = LoadLibrary (plugin->full_name);
+ if (!dl_handle)
+ {
+ char *err = win32_error_msg ();
+ error ("cannot load plugin %s\n%s", plugin->full_name, err);
+ LocalFree (err);
+ return false;
+ }
+
+ /* Check the plugin license. Unlike the name suggests, GetProcAddress()
+ can be used for both functions and variables. */
+ if (GetProcAddress (dl_handle, str_license) == NULL)
+ {
+ char *err = win32_error_msg ();
+ fatal_error (input_location,
+ "plugin %s is not licensed under a GPL-compatible license\n"
+ "%s", plugin->full_name, err);
+ }
+
+ /* Unlike dlsym(), GetProcAddress() returns a pointer to a function so we
+ can cast directly without union tricks. */
+ plugin_init = (plugin_init_func)
+ GetProcAddress (dl_handle, str_plugin_init_func_name);
+
+ if (plugin_init == NULL)
+ {
+ char *err = win32_error_msg ();
+ FreeLibrary (dl_handle);
+ error ("cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
+ plugin->full_name, err);
+ LocalFree (err);
+ return false;
+ }
+
+ /* Call the plugin-provided initialization routine with the arguments. */
+ if ((*plugin_init) (plugin, &gcc_version))
+ {
+ FreeLibrary (dl_handle);
+ error ("fail to initialize plugin %s", plugin->full_name);
+ return false;
+ }
+ /* Leak dl_handle on purpose to ensure the plugin is loaded for the
+ entire run of the compiler. */
+ return true;
+}
+
+#else // POSIX-like with dlopen()/dlsym().
+
/* We need a union to cast dlsym return value to a function pointer
as ISO C forbids assignment between function pointer and 'void *'.
Use explicit union instead of __extension__(<union_cast>) for
@@ -581,8 +685,6 @@ invoke_plugin_callbacks_full (int event, void *gcc_data)
#define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
#define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
-/* Try to initialize PLUGIN. Return true if successful. */
-
static bool
try_init_one_plugin (struct plugin_name_args *plugin)
{
@@ -634,7 +736,7 @@ try_init_one_plugin (struct plugin_name_args *plugin)
entire run of the compiler. */
return true;
}
-
+#endif
/* Routine to dlopen and initialize one plugin. This function is passed to
(and called by) the hash table traverse routine. Return 1 for the
diff --git a/libcc1/ChangeLog b/libcc1/ChangeLog
index ba77d02902d..c248bf8dd20 100644
--- a/libcc1/ChangeLog
+++ b/libcc1/ChangeLog
@@ -1,3 +1,7 @@
+2017-11-14 Boris Kolpackov <boris@codesynthesis.com>
+
+ * configure: Regenerate.
+
2017-11-16 Sergio Durigan Junior <sergiodj@redhat.com>
Pedro Alves <palves@redhat.com>
diff --git a/libcc1/configure b/libcc1/configure
index d6f480fe930..23d1a7645ff 100755
--- a/libcc1/configure
+++ b/libcc1/configure
@@ -14552,8 +14552,21 @@ fi
pluginlibs=
+ plugin_check=yes
case "${host}" in
+ *-*-mingw*)
+ # Since plugin support under MinGW is not as straightforward as on
+ # other platforms (e.g., we have to link import library, etc), we
+ # only enable it if explicitly requested.
+ if test x"$default_plugin" = x"yes"; then
+ enable_plugin=no
+ elif test x"$enable_plugin" = x"yes"; then
+ # Use make's target variable to derive import library name.
+ pluginlibs='-Wl,--export-all-symbols -Wl,--out-implib=$@.a'
+ plugin_check=no
+ fi
+ ;;
*-*-darwin*)
if test x$build = x$host; then
export_sym_check="nm${exeext} -g"
@@ -14574,7 +14587,7 @@ fi
;;
esac
- if test x"$enable_plugin" = x"yes"; then
+ if test x"$enable_plugin" = x"yes" -a x"$plugin_check" = x"yes"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for exported symbols" >&5
$as_echo_n "checking for exported symbols... " >&6; }