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
This commit is contained in:
Boris Kolpackov 2017-11-26 13:00:48 +00:00 committed by Jonathan Yong
parent 44dfb82280
commit 8c7dbea9f1
13 changed files with 253 additions and 20 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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 $@; \
}

View File

@ -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

View File

@ -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:
#

15
gcc/configure vendored
View File

@ -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; }

View File

@ -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

View File

@ -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)

View File

@ -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.

View File

@ -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

View File

@ -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>

15
libcc1/configure vendored
View File

@ -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; }