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:
parent
44dfb82280
commit
8c7dbea9f1
13 changed files with 253 additions and 20 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 $@; \
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
15
gcc/configure
vendored
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
120
gcc/plugin.c
120
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
|
||||
|
|
|
@ -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
15
libcc1/configure
vendored
|
@ -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; }
|
||||
|
|
Loading…
Add table
Reference in a new issue