+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.
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"
;;
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
+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
build=@build@
host=@host@
host_noncanonical=@host_noncanonical@
+host_os=@host_os@
target=@target@
target_noncanonical:=@target_noncanonical@
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@
$(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 $@; \
}
+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
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:
#\f
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"
;;
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; }
+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
$(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)
@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.
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
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.
#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)
/* 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;
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,
}
#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
#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)
{
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
+2017-11-14 Boris Kolpackov <boris@codesynthesis.com>
+
+ * configure: Regenerate.
+
2017-11-16 Sergio Durigan Junior <sergiodj@redhat.com>
Pedro Alves <palves@redhat.com>
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"
;;
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; }