diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2017-11-26 13:00:48 +0000 |
---|---|---|
committer | Jonathan Yong <jyong@gcc.gnu.org> | 2017-11-26 13:00:48 +0000 |
commit | 8c7dbea9f193ae21d193453d7a9eb6d2089618d6 (patch) | |
tree | c02088e446e880dcebb2359db9e0c6d8c5681dd2 /gcc/plugin.c | |
parent | 44dfb822801cb19dd842c5eaa2bbfa3b64b375f7 (diff) | |
download | gcc-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.c | 120 |
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 |