Commit 8c7dbea9 by Boris Kolpackov Committed by Jonathan Yong

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.

From-SVN: r255154
parent 44dfb822
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> 2017-11-17 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
* cet.m4: New file. * cet.m4: New file.
......
...@@ -19,8 +19,21 @@ AC_DEFUN([GCC_ENABLE_PLUGINS], ...@@ -19,8 +19,21 @@ AC_DEFUN([GCC_ENABLE_PLUGINS],
enable_plugin=yes; default_plugin=yes) enable_plugin=yes; default_plugin=yes)
pluginlibs= pluginlibs=
plugin_check=yes
case "${host}" in 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*) *-*-darwin*)
if test x$build = x$host; then if test x$build = x$host; then
export_sym_check="nm${exeext} -g" export_sym_check="nm${exeext} -g"
...@@ -41,7 +54,7 @@ AC_DEFUN([GCC_ENABLE_PLUGINS], ...@@ -41,7 +54,7 @@ AC_DEFUN([GCC_ENABLE_PLUGINS],
;; ;;
esac 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]) AC_MSG_CHECKING([for exported symbols])
if test "x$export_sym_check" != x; then if test "x$export_sym_check" != x; then
......
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> 2017-11-25 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/81553 PR rtl-optimization/81553
...@@ -57,6 +57,7 @@ MAKEOVERRIDES = ...@@ -57,6 +57,7 @@ MAKEOVERRIDES =
build=@build@ build=@build@
host=@host@ host=@host@
host_noncanonical=@host_noncanonical@ host_noncanonical=@host_noncanonical@
host_os=@host_os@
target=@target@ target=@target@
target_noncanonical:=@target_noncanonical@ target_noncanonical:=@target_noncanonical@
...@@ -393,6 +394,11 @@ PLUGINLIBS = @pluginlibs@ ...@@ -393,6 +394,11 @@ PLUGINLIBS = @pluginlibs@
enable_plugin = @enable_plugin@ 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_host_shared = @enable_host_shared@
enable_as_accelerator = @enable_as_accelerator@ enable_as_accelerator = @enable_as_accelerator@
...@@ -2828,11 +2834,15 @@ $(genprog:%=build/gen%$(build_exeext)): build/gen%$(build_exeext): build/gen%.o ...@@ -2828,11 +2834,15 @@ $(genprog:%=build/gen%$(build_exeext)): build/gen%$(build_exeext): build/gen%.o
$(filter-out $(BUILD_LIBDEPS), $^) $(BUILD_LIBS) $(filter-out $(BUILD_LIBDEPS), $^) $(BUILD_LIBS)
# Generated source files for gengtype. Prepend inclusion of # 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. # any system header is included.
gengtype-lex.c : gengtype-lex.l gengtype-lex.c : gengtype-lex.l
-$(FLEX) $(FLEXFLAGS) -o$@ $< && { \ -$(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; \ cat $@ >> $@.tmp; \
mv $@.tmp $@; \ mv $@.tmp $@; \
} }
......
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> 2017-11-23 Jakub Jelinek <jakub@redhat.com>
* c-parser.c (c_parser_omp_declare_simd): Reject declare simd in * c-parser.c (c_parser_omp_declare_simd): Reject declare simd in
......
...@@ -125,7 +125,14 @@ check-c : check-gcc ...@@ -125,7 +125,14 @@ check-c : check-gcc
c.install-common: c.install-common:
c.install-man: 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: c.uninstall:
# #
......
...@@ -29619,8 +29619,21 @@ fi ...@@ -29619,8 +29619,21 @@ fi
pluginlibs= pluginlibs=
plugin_check=yes
case "${host}" in 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*) *-*-darwin*)
if test x$build = x$host; then if test x$build = x$host; then
export_sym_check="nm${exeext} -g" export_sym_check="nm${exeext} -g"
...@@ -29641,7 +29654,7 @@ fi ...@@ -29641,7 +29654,7 @@ fi
;; ;;
esac 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 "$as_me:${as_lineno-$LINENO}: checking for exported symbols" >&5
$as_echo_n "checking for exported symbols... " >&6; } $as_echo_n "checking for exported symbols... " >&6; }
......
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> 2017-11-23 Jakub Jelinek <jakub@redhat.com>
* parser.c (cp_parser_omp_declare): Change return type to bool from * parser.c (cp_parser_omp_declare): Change return type to bool from
......
...@@ -238,6 +238,11 @@ c++.install-plugin: installdirs ...@@ -238,6 +238,11 @@ c++.install-plugin: installdirs
$(mkinstalldirs) $(DESTDIR)$$dir; \ $(mkinstalldirs) $(DESTDIR)$$dir; \
$(INSTALL_DATA) $$path $(DESTDIR)$$dest; \ $(INSTALL_DATA) $$path $(DESTDIR)$$dest; \
done 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: c++.uninstall:
-rm -rf $(DESTDIR)$(bindir)/$(CXX_INSTALL_NAME)$(exeext) -rm -rf $(DESTDIR)$(bindir)/$(CXX_INSTALL_NAME)$(exeext)
......
...@@ -34,14 +34,17 @@ can be quite useful. ...@@ -34,14 +34,17 @@ can be quite useful.
@section Loading Plugins @section Loading Plugins
Plugins are supported on platforms that support @option{-ldl Plugins are supported on platforms that support @option{-ldl
-rdynamic}. They are loaded by the compiler using @code{dlopen} -rdynamic} as well as Windows/MinGW. They are loaded by the compiler
and invoked at pre-determined locations in the compilation using @code{dlopen} or equivalent and invoked at pre-determined
process. locations in the compilation process.
Plugins are loaded with 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 The plugin arguments are parsed by GCC and passed to respective
plugins as key-value pairs. Multiple plugins can be invoked by plugins as key-value pairs. Multiple plugins can be invoked by
specifying multiple @option{-fplugin} arguments. specifying multiple @option{-fplugin} arguments.
...@@ -49,7 +52,7 @@ 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 A plugin can be simply given by its short name (no dots or
slashes). When simply passing @option{-fplugin=@var{name}}, the plugin is slashes). When simply passing @option{-fplugin=@var{name}}, the plugin is
loaded from the @file{plugin} directory, so @option{-fplugin=@var{name}} 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. using backquote shell syntax to query the @file{plugin} directory.
@node Plugin API @node Plugin API
...@@ -508,6 +511,48 @@ A single source file plugin may be built with @code{g++ -I`gcc ...@@ -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} plugin.so}, using backquote shell syntax to query the @file{plugin}
directory. 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 When a plugin needs to use @command{gengtype}, be sure that both
@file{gengtype} and @file{gtype.state} have the same version as the @file{gengtype} and @file{gtype.state} have the same version as the
GCC for which the plugin is built. GCC for which the plugin is built.
...@@ -34,6 +34,16 @@ along with GCC; see the file COPYING3. If not see ...@@ -34,6 +34,16 @@ along with GCC; see the file COPYING3. If not see
#include "plugin-version.h" #include "plugin-version.h"
#endif #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_STRINGIFY0(X) #X
#define GCC_PLUGIN_STRINGIFY1(X) GCC_PLUGIN_STRINGIFY0 (X) #define GCC_PLUGIN_STRINGIFY1(X) GCC_PLUGIN_STRINGIFY0 (X)
...@@ -144,7 +154,7 @@ get_plugin_base_name (const char *full_name) ...@@ -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. */ /* First get the base name part of the full-path name, i.e. NAME.so. */
char *base_name = xstrdup (lbasename (full_name)); 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)); strip_off_ending (base_name, strlen (base_name));
return base_name; return base_name;
...@@ -175,12 +185,27 @@ add_new_plugin (const char* plugin_name) ...@@ -175,12 +185,27 @@ add_new_plugin (const char* plugin_name)
if (name_is_short) if (name_is_short)
{ {
base_name = CONST_CAST (char*, plugin_name); 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. #if defined(__MINGW32__)
When plugins shall be available on non ELF systems such as static const char plugin_ext[] = ".dll";
Windows or MacOS, this code has to be greatly improved. */ #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 = concat (default_plugin_dir_name (), "/",
plugin_name, ".so", NULL); plugin_name, plugin_ext, NULL);
if (access (plugin_name, R_OK)) if (access (plugin_name, R_OK))
fatal_error fatal_error
(input_location, (input_location,
...@@ -573,6 +598,85 @@ invoke_plugin_callbacks_full (int event, void *gcc_data) ...@@ -573,6 +598,85 @@ invoke_plugin_callbacks_full (int event, void *gcc_data)
} }
#ifdef ENABLE_PLUGIN #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 /* We need a union to cast dlsym return value to a function pointer
as ISO C forbids assignment between function pointer and 'void *'. as ISO C forbids assignment between function pointer and 'void *'.
Use explicit union instead of __extension__(<union_cast>) for Use explicit union instead of __extension__(<union_cast>) for
...@@ -581,8 +685,6 @@ invoke_plugin_callbacks_full (int event, void *gcc_data) ...@@ -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_VOID_PTR(NAME) (NAME._q)
#define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq) #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
/* Try to initialize PLUGIN. Return true if successful. */
static bool static bool
try_init_one_plugin (struct plugin_name_args *plugin) try_init_one_plugin (struct plugin_name_args *plugin)
{ {
...@@ -634,7 +736,7 @@ 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. */ entire run of the compiler. */
return true; return true;
} }
#endif
/* Routine to dlopen and initialize one plugin. This function is passed to /* Routine to dlopen and initialize one plugin. This function is passed to
(and called by) the hash table traverse routine. Return 1 for the (and called by) the hash table traverse routine. Return 1 for the
......
2017-11-14 Boris Kolpackov <boris@codesynthesis.com>
* configure: Regenerate.
2017-11-16 Sergio Durigan Junior <sergiodj@redhat.com> 2017-11-16 Sergio Durigan Junior <sergiodj@redhat.com>
Pedro Alves <palves@redhat.com> Pedro Alves <palves@redhat.com>
......
...@@ -14552,8 +14552,21 @@ fi ...@@ -14552,8 +14552,21 @@ fi
pluginlibs= pluginlibs=
plugin_check=yes
case "${host}" in 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*) *-*-darwin*)
if test x$build = x$host; then if test x$build = x$host; then
export_sym_check="nm${exeext} -g" export_sym_check="nm${exeext} -g"
...@@ -14574,7 +14587,7 @@ fi ...@@ -14574,7 +14587,7 @@ fi
;; ;;
esac 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 "$as_me:${as_lineno-$LINENO}: checking for exported symbols" >&5
$as_echo_n "checking for exported symbols... " >&6; } $as_echo_n "checking for exported symbols... " >&6; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment