aboutsummaryrefslogtreecommitdiff
path: root/gcc/plugin.c
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-11-26 13:00:48 +0000
committerJonathan Yong <jyong@gcc.gnu.org>2017-11-26 13:00:48 +0000
commit8c7dbea9f193ae21d193453d7a9eb6d2089618d6 (patch)
treec02088e446e880dcebb2359db9e0c6d8c5681dd2 /gcc/plugin.c
parent44dfb822801cb19dd842c5eaa2bbfa3b64b375f7 (diff)
downloadgcc-8c7dbea9f193ae21d193453d7a9eb6d2089618d6.zip
gcc-8c7dbea9f193ae21d193453d7a9eb6d2089618d6.tar.gz
gcc-8c7dbea9f193ae21d193453d7a9eb6d2089618d6.tar.bz2
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
Diffstat (limited to 'gcc/plugin.c')
-rw-r--r--gcc/plugin.c120
1 files changed, 111 insertions, 9 deletions
diff --git a/gcc/plugin.c b/gcc/plugin.c
index 9892748..db18e64 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