| From c83027f32d9cca84959c7d6a1e519a0129731501 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Nicol=C3=A1s=20B=C3=A9rtolo?= <nicolasbertolo@gmail.com> |
| Date: Fri, 22 May 2020 17:54:41 -0300 |
| Subject: [PATCH] jit: port libgccjit to Windows |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| 2020-05-28 Nicolas Bértolo <nicolasbertolo@gmail.com> |
| |
| /ChangeLog: |
| * configure.ac: Don't require --enable-host-shared when building |
| for Mingw. |
| * configure: Regenerate. |
| |
| 2020-05-28 Nicolas Bértolo <nicolasbertolo@gmail.com> |
| |
| gcc/ChangeLog: |
| * Makefile.in: don't look for libiberty in the "pic" subdirectory |
| when building for Mingw. Add dependency on xgcc with the proper |
| extension. |
| |
| 2020-05-28 Nicolas Bértolo <nicolasbertolo@gmail.com> |
| |
| gcc/c/ChangeLog: |
| * Make-lang.in: Remove extra slash. |
| |
| 2020-05-28 Nicolas Bértolo <nicolasbertolo@gmail.com> |
| |
| gcc/jit/ChangeLog: |
| * Make-lang.in: Remove extra slash. Build libgccjit.dll and its |
| import library in Windows. |
| * config-lang.in: Update comment about --enable-host-shared. |
| * jit-w32.h: New file. |
| * jit-w32.c: New file. |
| (print_last_error): New function that prints the error |
| string corresponding to GetLastError(). |
| (get_TOKEN_USER_current_user): Helper function used for getting |
| the SID belonging to the current user. |
| (create_directory_for_current_user): Helper function to create |
| a directory with permissions such that only the current user can |
| access it. |
| (win_mkdtemp): Create a temporary directory using Windows APIs. |
| * jit-playback.c: Do not chmod files in Windows. Use LoadLibrary, |
| FreeLibrary and GetProcAddress instead of libdl. |
| * jit-result.h, jit-result.c: Introduce result::handle_t to |
| abstract over the types used for dynamic library handles. |
| * jit-tempdir.c: Do not use mkdtemp() in Windows, use |
| win_mkdtemp(). |
| --- |
| configure | 32 +++--- |
| configure.ac | 33 +++--- |
| gcc/Makefile.in | 10 +- |
| gcc/c/Make-lang.in | 2 +- |
| gcc/jit/Make-lang.in | 56 +++++++-- |
| gcc/jit/config-lang.in | 2 +- |
| gcc/jit/jit-playback.c | 24 +++- |
| gcc/jit/jit-result.c | 35 +++++- |
| gcc/jit/jit-result.h | 14 ++- |
| gcc/jit/jit-tempdir.c | 10 ++ |
| gcc/jit/jit-w32.c | 255 +++++++++++++++++++++++++++++++++++++++++ |
| gcc/jit/jit-w32.h | 30 +++++ |
| 12 files changed, 452 insertions(+), 51 deletions(-) |
| create mode 100644 gcc/jit/jit-w32.c |
| create mode 100644 gcc/jit/jit-w32.h |
| |
| diff --git a/configure b/configure |
| index 3af6a530b9a..b7897446c70 100755 |
| --- a/configure |
| +++ b/configure |
| @@ -6489,9 +6489,13 @@ $as_echo "$as_me: WARNING: GNAT is required to build $language" >&2;} |
| esac |
| |
| # Disable jit if -enable-host-shared not specified |
| - case ${add_this_lang}:${language}:${host_shared} in |
| - yes:jit:no) |
| - # PR jit/64780: explicitly specify --enable-host-shared |
| + # but not if building for Mingw |
| + case $target in |
| + *mingw*) ;; |
| + *) |
| + case ${add_this_lang}:${language}:${host_shared} in |
| + yes:jit:no) |
| + # PR jit/64780: explicitly specify --enable-host-shared |
| as_fn_error $? " |
| Enabling language \"jit\" requires --enable-host-shared. |
| |
| @@ -6502,17 +6506,19 @@ If you want to build both the jit and the regular compiler, it is often |
| best to do this via two separate configure/builds, in separate |
| directories, to avoid imposing the performance cost of |
| --enable-host-shared on the regular compiler." "$LINENO" 5 |
| - ;; |
| - all:jit:no) |
| - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-host-shared required to build $language" >&5 |
| + ;; |
| + all:jit:no) |
| + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-host-shared required to build $language" >&5 |
| $as_echo "$as_me: WARNING: --enable-host-shared required to build $language" >&2;} |
| - add_this_lang=unsupported |
| - ;; |
| - *:jit:no) |
| - # Silently disable. |
| - add_this_lang=unsupported |
| - ;; |
| - esac |
| + add_this_lang=unsupported |
| + ;; |
| + *:jit:no) |
| + # Silently disable. |
| + add_this_lang=unsupported |
| + ;; |
| + esac |
| + ;; |
| + esac |
| |
| # Disable a language that is unsupported by the target. |
| case "${add_this_lang}: $unsupported_languages " in |
| diff --git a/configure.ac b/configure.ac |
| index a67801371a4..59bd92a3e53 100644 |
| --- a/configure.ac |
| +++ b/configure.ac |
| @@ -2079,9 +2079,14 @@ if test -d ${srcdir}/gcc; then |
| esac |
| |
| # Disable jit if -enable-host-shared not specified |
| - case ${add_this_lang}:${language}:${host_shared} in |
| - yes:jit:no) |
| - # PR jit/64780: explicitly specify --enable-host-shared |
| + # but not if building for Mingw. All code in Windows |
| + # is position independent code (PIC). |
| + case $target in |
| + *mingw*) ;; |
| + *) |
| + case ${add_this_lang}:${language}:${host_shared} in |
| + yes:jit:no) |
| + # PR jit/64780: explicitly specify --enable-host-shared |
| AC_MSG_ERROR([ |
| Enabling language "jit" requires --enable-host-shared. |
| |
| @@ -2092,16 +2097,18 @@ If you want to build both the jit and the regular compiler, it is often |
| best to do this via two separate configure/builds, in separate |
| directories, to avoid imposing the performance cost of |
| --enable-host-shared on the regular compiler.]) |
| - ;; |
| - all:jit:no) |
| - AC_MSG_WARN([--enable-host-shared required to build $language]) |
| - add_this_lang=unsupported |
| - ;; |
| - *:jit:no) |
| - # Silently disable. |
| - add_this_lang=unsupported |
| - ;; |
| - esac |
| + ;; |
| + all:jit:no) |
| + AC_MSG_WARN([--enable-host-shared required to build $language]) |
| + add_this_lang=unsupported |
| + ;; |
| + *:jit:no) |
| + # Silently disable. |
| + add_this_lang=unsupported |
| + ;; |
| + esac |
| + ;; |
| + esac |
| |
| # Disable a language that is unsupported by the target. |
| case "${add_this_lang}: $unsupported_languages " in |
| diff --git a/gcc/Makefile.in b/gcc/Makefile.in |
| index 0fe2ba241e3..45851eca815 100644 |
| --- a/gcc/Makefile.in |
| +++ b/gcc/Makefile.in |
| @@ -1046,10 +1046,12 @@ ALL_LINKERFLAGS = $(ALL_CXXFLAGS) |
| |
| # Build and host support libraries. |
| |
| -# Use the "pic" build of libiberty if --enable-host-shared. |
| +# Use the "pic" build of libiberty if --enable-host-shared, unless we are |
| +# building for mingw. |
| +LIBIBERTY_PICDIR=$(if $(findstring mingw,$(target)),,pic) |
| ifeq ($(enable_host_shared),yes) |
| -LIBIBERTY = ../libiberty/pic/libiberty.a |
| -BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/pic/libiberty.a |
| +LIBIBERTY = ../libiberty/$(LIBIBERTY_PICDIR)/libiberty.a |
| +BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/$(LIBIBERTY_PICDIR)/libiberty.a |
| else |
| LIBIBERTY = ../libiberty/libiberty.a |
| BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/libiberty.a |
| @@ -1726,7 +1728,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \ |
| # This symlink makes the full installation name of the driver be available |
| # from within the *build* directory, for use when running the JIT library |
| # from there (e.g. when running its testsuite). |
| -$(FULL_DRIVER_NAME): ./xgcc |
| +$(FULL_DRIVER_NAME): ./xgcc$(exeext) |
| rm -f $@ |
| $(LN_S) $< $@ |
| |
| diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in |
| index 8944b9b9f03..7efc7c2c332 100644 |
| --- a/gcc/c/Make-lang.in |
| +++ b/gcc/c/Make-lang.in |
| @@ -162,7 +162,7 @@ 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 |
| + $(INSTALL_DATA) cc1$(exeext).a $(DESTDIR)$(plugin_resourcesdir)/cc1$(exeext).a |
| endif |
| |
| c.uninstall: |
| diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in |
| index 38ddfad2889..9cb7814d6d5 100644 |
| --- a/gcc/jit/Make-lang.in |
| +++ b/gcc/jit/Make-lang.in |
| @@ -40,10 +40,19 @@ |
| # into the jit rule, but that needs a little bit of work |
| # to do the right thing within all.cross. |
| |
| +ifneq (,$(findstring mingw,$(target))) |
| +LIBGCCJIT_FILENAME = libgccjit.dll |
| + |
| +jit: $(LIBGCCJIT_FILENAME) \ |
| + $(FULL_DRIVER_NAME) |
| + |
| +else |
| + |
| LIBGCCJIT_LINKER_NAME = libgccjit.so |
| LIBGCCJIT_VERSION_NUM = 0 |
| LIBGCCJIT_MINOR_NUM = 0 |
| LIBGCCJIT_RELEASE_NUM = 1 |
| + |
| LIBGCCJIT_SONAME = $(LIBGCCJIT_LINKER_NAME).$(LIBGCCJIT_VERSION_NUM) |
| LIBGCCJIT_FILENAME = \ |
| $(LIBGCCJIT_SONAME).$(LIBGCCJIT_MINOR_NUM).$(LIBGCCJIT_RELEASE_NUM) |
| @@ -68,6 +77,7 @@ jit: $(LIBGCCJIT_FILENAME) \ |
| $(LIBGCCJIT_SYMLINK) \ |
| $(LIBGCCJIT_LINKER_NAME_SYMLINK) \ |
| $(FULL_DRIVER_NAME) |
| +endif |
| |
| # Tell GNU make to ignore these if they exist. |
| .PHONY: jit |
| @@ -84,9 +94,21 @@ jit_OBJS = attribs.o \ |
| jit/jit-spec.o \ |
| gcc.o |
| |
| +ifneq (,$(findstring mingw,$(target))) |
| +jit_OBJS += jit/jit-w32.o |
| +endif |
| + |
| # Use strict warnings for this front end. |
| jit-warn = $(STRICT_WARN) |
| |
| +ifneq (,$(findstring mingw,$(target))) |
| +# Create import library libgccjit.dll.a |
| +LIBGCCJIT_EXTRA_OPTS = -Wl,--out-implib,$(LIBGCCJIT_FILENAME).a |
| +else |
| +LIBGCCJIT_EXTRA_OPTS = $(LIBGCCJIT_VERSION_SCRIPT_OPTION) \ |
| + $(LIBGCCJIT_SONAME_OPTION) |
| +endif |
| + |
| # We avoid using $(BACKEND) from Makefile.in in order to avoid pulling |
| # in main.o |
| $(LIBGCCJIT_FILENAME): $(jit_OBJS) \ |
| @@ -98,14 +120,16 @@ $(LIBGCCJIT_FILENAME): $(jit_OBJS) \ |
| $(jit_OBJS) libbackend.a libcommon-target.a libcommon.a \ |
| $(CPPLIB) $(LIBDECNUMBER) $(EXTRA_GCC_LIBS) $(LIBS) $(BACKENDLIBS) \ |
| $(EXTRA_GCC_OBJS) \ |
| - $(LIBGCCJIT_VERSION_SCRIPT_OPTION) \ |
| - $(LIBGCCJIT_SONAME_OPTION) |
| + $(LIBGCCJIT_EXTRA_OPTS) |
| |
| +# Create symlinks when not building for Windows |
| +ifeq (,$(findstring mingw,$(target))) |
| $(LIBGCCJIT_SONAME_SYMLINK): $(LIBGCCJIT_FILENAME) |
| ln -sf $(LIBGCCJIT_FILENAME) $(LIBGCCJIT_SONAME_SYMLINK) |
| |
| $(LIBGCCJIT_LINKER_NAME_SYMLINK): $(LIBGCCJIT_SONAME_SYMLINK) |
| ln -sf $(LIBGCCJIT_SONAME_SYMLINK) $(LIBGCCJIT_LINKER_NAME_SYMLINK) |
| +endif |
| |
| # |
| # Build hooks: |
| @@ -275,19 +299,31 @@ selftest-jit: |
| |
| # |
| # Install hooks: |
| -jit.install-common: installdirs |
| +jit.install-headers: |
| + $(INSTALL_DATA) $(srcdir)/jit/libgccjit.h \ |
| + $(DESTDIR)$(includedir)/libgccjit.h |
| + $(INSTALL_DATA) $(srcdir)/jit/libgccjit++.h \ |
| + $(DESTDIR)$(includedir)/libgccjit++.h |
| + |
| +ifneq (,$(findstring mingw,$(target))) |
| +jit.install-common: installdirs jit.install-headers |
| +# Install import library |
| + $(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME).a \ |
| + $(DESTDIR)$(libdir)/$(LIBGCCJIT_FILENAME).a |
| +# Install DLL file |
| $(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \ |
| - $(DESTDIR)/$(libdir)/$(LIBGCCJIT_FILENAME) |
| + $(DESTDIR)$(bindir)/$(LIBGCCJIT_FILENAME) |
| +else |
| +jit.install-common: installdirs jit.install-headers |
| + $(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \ |
| + $(DESTDIR)$(libdir)/$(LIBGCCJIT_FILENAME) |
| ln -sf \ |
| $(LIBGCCJIT_FILENAME) \ |
| - $(DESTDIR)/$(libdir)/$(LIBGCCJIT_SONAME_SYMLINK) |
| + $(DESTDIR)$(libdir)/$(LIBGCCJIT_SONAME_SYMLINK) |
| ln -sf \ |
| $(LIBGCCJIT_SONAME_SYMLINK)\ |
| - $(DESTDIR)/$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK) |
| - $(INSTALL_DATA) $(srcdir)/jit/libgccjit.h \ |
| - $(DESTDIR)/$(includedir)/libgccjit.h |
| - $(INSTALL_DATA) $(srcdir)/jit/libgccjit++.h \ |
| - $(DESTDIR)/$(includedir)/libgccjit++.h |
| + $(DESTDIR)$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK) |
| +endif |
| |
| jit.install-man: |
| |
| diff --git a/gcc/jit/config-lang.in b/gcc/jit/config-lang.in |
| index 89e3bfe0a51..f8ef6042b39 100644 |
| --- a/gcc/jit/config-lang.in |
| +++ b/gcc/jit/config-lang.in |
| @@ -32,7 +32,7 @@ target_libs="" |
| gtfiles="\$(srcdir)/jit/dummy-frontend.c" |
| |
| # The configuration requires --enable-host-shared |
| -# for jit to be supported. |
| +# for jit to be supported (only when not building for Mingw). |
| # Hence to get the jit, one must configure with: |
| # --enable-host-shared --enable-languages=jit |
| build_by_default="no" |
| diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c |
| index d2c8bb4c154..0fddf04da87 100644 |
| --- a/gcc/jit/jit-playback.c |
| +++ b/gcc/jit/jit-playback.c |
| @@ -47,6 +47,10 @@ along with GCC; see the file COPYING3. If not see |
| #include "jit-builtins.h" |
| #include "jit-tempdir.h" |
| |
| +#ifdef _WIN32 |
| +#include "jit-w32.h" |
| +#endif |
| + |
| /* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD, |
| SET_DECL_C_BIT_FIELD. |
| These are redefined here to avoid depending from the C frontend. */ |
| @@ -2159,8 +2163,10 @@ playback::compile_to_file::copy_file (const char *src_path, |
| |
| gcc_assert (total_sz_in == total_sz_out); |
| if (get_logger ()) |
| - get_logger ()->log ("total bytes copied: %ld", total_sz_out); |
| + get_logger ()->log ("total bytes copied: %zu", total_sz_out); |
| |
| + /* fchmod does not exist in Windows. */ |
| +#ifndef _WIN32 |
| /* Set the permissions of the copy to those of the original file, |
| in particular the "executable" bits. */ |
| if (fchmod (fileno (f_out), stat_buf.st_mode) == -1) |
| @@ -2168,6 +2174,7 @@ playback::compile_to_file::copy_file (const char *src_path, |
| "error setting mode of %s: %s", |
| dst_path, |
| xstrerror (errno)); |
| +#endif |
| |
| fclose (f_out); |
| } |
| @@ -2644,10 +2651,19 @@ dlopen_built_dso () |
| { |
| JIT_LOG_SCOPE (get_logger ()); |
| auto_timevar load_timevar (get_timer (), TV_LOAD); |
| - void *handle = NULL; |
| - const char *error = NULL; |
| + result::handle handle = NULL; |
| result *result_obj = NULL; |
| |
| +#ifdef _WIN32 |
| + /* Clear any existing error. */ |
| + SetLastError(0); |
| + |
| + handle = LoadLibrary(m_tempdir->get_path_so_file ()); |
| + if (GetLastError() != 0) { |
| + print_last_error(); |
| + } |
| +#else |
| + const char *error = NULL; |
| /* Clear any existing error. */ |
| dlerror (); |
| |
| @@ -2656,6 +2672,8 @@ dlopen_built_dso () |
| if ((error = dlerror()) != NULL) { |
| add_error (NULL, "%s", error); |
| } |
| +#endif |
| + |
| if (handle) |
| { |
| /* We've successfully dlopened the result; create a |
| diff --git a/gcc/jit/jit-result.c b/gcc/jit/jit-result.c |
| index c10e5a13c30..63362641216 100644 |
| --- a/gcc/jit/jit-result.c |
| +++ b/gcc/jit/jit-result.c |
| @@ -27,13 +27,17 @@ along with GCC; see the file COPYING3. If not see |
| #include "jit-result.h" |
| #include "jit-tempdir.h" |
| |
| +#ifdef _WIN32 |
| +#include "jit-w32.h" |
| +#endif |
| + |
| namespace gcc { |
| namespace jit { |
| |
| /* Constructor for gcc::jit::result. */ |
| |
| result:: |
| -result(logger *logger, void *dso_handle, tempdir *tempdir_) : |
| +result(logger *logger, handle dso_handle, tempdir *tempdir_) : |
| log_user (logger), |
| m_dso_handle (dso_handle), |
| m_tempdir (tempdir_) |
| @@ -49,8 +53,11 @@ result::~result() |
| { |
| JIT_LOG_SCOPE (get_logger ()); |
| |
| +#ifdef _WIN32 |
| + FreeLibrary(m_dso_handle); |
| +#else |
| dlclose (m_dso_handle); |
| - |
| +#endif |
| /* Responsibility for cleaning up the tempdir (including "fake.so" within |
| the filesystem) might have been handed to us by the playback::context, |
| so that the cleanup can be delayed (see PR jit/64206). |
| @@ -72,8 +79,17 @@ get_code (const char *funcname) |
| JIT_LOG_SCOPE (get_logger ()); |
| |
| void *code; |
| - const char *error; |
| |
| +#ifdef _WIN32 |
| + /* Clear any existing error. */ |
| + SetLastError(0); |
| + |
| + code = (void *)GetProcAddress(m_dso_handle, funcname); |
| + if (GetLastError() != 0) { |
| + print_last_error (); |
| + } |
| +#else |
| + const char *error; |
| /* Clear any existing error. */ |
| dlerror (); |
| |
| @@ -82,6 +98,7 @@ get_code (const char *funcname) |
| if ((error = dlerror()) != NULL) { |
| fprintf(stderr, "%s\n", error); |
| } |
| +#endif |
| |
| return code; |
| } |
| @@ -99,8 +116,17 @@ get_global (const char *name) |
| JIT_LOG_SCOPE (get_logger ()); |
| |
| void *global; |
| - const char *error; |
| |
| +#ifdef _WIN32 |
| + /* Clear any existing error. */ |
| + SetLastError(0); |
| + |
| + global = (void *)GetProcAddress(m_dso_handle, name); |
| + if (GetLastError() != 0) { |
| + print_last_error (); |
| + } |
| +#else |
| + const char *error; |
| /* Clear any existing error. */ |
| dlerror (); |
| |
| @@ -109,6 +135,7 @@ get_global (const char *name) |
| if ((error = dlerror()) != NULL) { |
| fprintf(stderr, "%s\n", error); |
| } |
| +#endif |
| |
| return global; |
| } |
| diff --git a/gcc/jit/jit-result.h b/gcc/jit/jit-result.h |
| index 02586060368..d8e940aafb0 100644 |
| --- a/gcc/jit/jit-result.h |
| +++ b/gcc/jit/jit-result.h |
| @@ -21,6 +21,10 @@ along with GCC; see the file COPYING3. If not see |
| #ifndef JIT_RESULT_H |
| #define JIT_RESULT_H |
| |
| +#ifdef _WIN32 |
| +#include <minwindef.h> |
| +#endif |
| + |
| namespace gcc { |
| |
| namespace jit { |
| @@ -29,7 +33,13 @@ namespace jit { |
| class result : public log_user |
| { |
| public: |
| - result(logger *logger, void *dso_handle, tempdir *tempdir_); |
| +#ifdef _WIN32 |
| + typedef HMODULE handle; |
| +#else |
| + typedef void* handle; |
| +#endif |
| + |
| + result(logger *logger, handle dso_handle, tempdir *tempdir_); |
| |
| virtual ~result(); |
| |
| @@ -40,7 +50,7 @@ public: |
| get_global (const char *name); |
| |
| private: |
| - void *m_dso_handle; |
| + handle m_dso_handle; |
| tempdir *m_tempdir; |
| }; |
| |
| diff --git a/gcc/jit/jit-tempdir.c b/gcc/jit/jit-tempdir.c |
| index 10c528faf28..050d53409ca 100644 |
| --- a/gcc/jit/jit-tempdir.c |
| +++ b/gcc/jit/jit-tempdir.c |
| @@ -24,7 +24,11 @@ along with GCC; see the file COPYING3. If not see |
| |
| #include "jit-tempdir.h" |
| |
| +#ifdef _WIN32 |
| +#include "jit-w32.h" |
| +#endif |
| |
| +#ifndef _WIN32 |
| /* Construct a tempdir path template suitable for use by mkdtemp |
| e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in |
| libiberty's choose_tempdir rather than hardcoding "/tmp/". |
| @@ -62,6 +66,7 @@ make_tempdir_path_template () |
| |
| return result; |
| } |
| +#endif |
| |
| /* The constructor for the jit::tempdir object. |
| The real work is done by the jit::tempdir::create method. */ |
| @@ -87,6 +92,9 @@ gcc::jit::tempdir::create () |
| { |
| JIT_LOG_SCOPE (get_logger ()); |
| |
| +#ifdef _WIN32 |
| + m_path_tempdir = win_mkdtemp (); |
| +#else |
| m_path_template = make_tempdir_path_template (); |
| if (!m_path_template) |
| return false; |
| @@ -97,6 +105,8 @@ gcc::jit::tempdir::create () |
| is unique. Hence no other (non-root) users should have access to |
| the paths within it. */ |
| m_path_tempdir = mkdtemp (m_path_template); |
| +#endif |
| + |
| if (!m_path_tempdir) |
| return false; |
| log ("m_path_tempdir: %s", m_path_tempdir); |
| diff --git a/gcc/jit/jit-w32.c b/gcc/jit/jit-w32.c |
| new file mode 100644 |
| index 00000000000..f24f4f0c941 |
| --- /dev/null |
| +++ b/gcc/jit/jit-w32.c |
| @@ -0,0 +1,255 @@ |
| +/* Functions used by the Windows port of libgccjit. |
| + Copyright (C) 2020 Free Software Foundation, Inc. |
| + Contributed by Nicolas Bertolo <nicolasbertolo@gmail.com>. |
| + |
| +This file is part of GCC. |
| + |
| +GCC is free software; you can redistribute it and/or modify it |
| +under the terms of the GNU General Public License as published by |
| +the Free Software Foundation; either version 3, or (at your option) |
| +any later version. |
| + |
| +GCC is distributed in the hope that it will be useful, but |
| +WITHOUT ANY WARRANTY; without even the implied warranty of |
| +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| +General Public License for more details. |
| + |
| +You should have received a copy of the GNU General Public License |
| +along with GCC; see the file COPYING3. If not see |
| +<http://www.gnu.org/licenses/>. */ |
| + |
| +#include "config.h" |
| + |
| +/* Required for rand_s */ |
| +#define _CRT_RAND_S |
| + |
| +#include <cstdio> |
| +#include <cstdint> |
| + |
| +#include "jit-w32.h" |
| + |
| +#include "libiberty.h" |
| + |
| +#include <accctrl.h> |
| +#include <aclapi.h> |
| + |
| +namespace gcc { |
| +namespace jit { |
| +void |
| +print_last_error (void) |
| +{ |
| + LPSTR psz = NULL; |
| + DWORD dwErrorCode; |
| + dwErrorCode = GetLastError(); |
| + const DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
| + | FORMAT_MESSAGE_IGNORE_INSERTS |
| + | FORMAT_MESSAGE_ALLOCATE_BUFFER |
| + | FORMAT_MESSAGE_MAX_WIDTH_MASK, |
| + NULL, |
| + dwErrorCode, |
| + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
| + reinterpret_cast<LPSTR>(&psz), |
| + 0, |
| + NULL); |
| + if (cchMsg > 0) |
| + { |
| + fprintf (stderr, "%s\n", psz); |
| + LocalFree (psz); |
| + } |
| + else |
| + { |
| + fprintf (stderr, "Failed to retrieve error message string for error %lu\n", |
| + dwErrorCode); |
| + } |
| +} |
| + |
| +/* Helper function used for getting the SID belonging to the current user. */ |
| +static TOKEN_USER* |
| +get_TOKEN_USER_current_user () |
| +{ |
| + TOKEN_USER *result = NULL; |
| + |
| + HANDLE process_token = INVALID_HANDLE_VALUE; |
| + |
| + DWORD token_user_info_len; |
| + TOKEN_USER *token_user = NULL; |
| + |
| + /* Get current process access token. */ |
| + if (!OpenProcessToken (GetCurrentProcess (), TOKEN_READ, |
| + &process_token)) |
| + return NULL; |
| + |
| + /* Get necessary buffer size. */ |
| + if (!GetTokenInformation(process_token, TokenUser, NULL, 0, &token_user_info_len) |
| + && GetLastError() != ERROR_INSUFFICIENT_BUFFER) |
| + goto cleanup; |
| + |
| + token_user = (TOKEN_USER*) new char[token_user_info_len]; |
| + |
| + /* Get info about the user of the process */ |
| + if (!GetTokenInformation (process_token, TokenUser, token_user, |
| + token_user_info_len, &token_user_info_len)) |
| + goto cleanup; |
| + |
| + result = token_user; |
| + |
| + cleanup: |
| + if (process_token != INVALID_HANDLE_VALUE) |
| + CloseHandle(process_token); |
| + |
| + if (token_user != NULL && result == NULL) |
| + delete[] (char*)token_user; |
| + |
| + return result; |
| +} |
| + |
| +/* Helper function to create a directory with permissions such that only the |
| + current user can access it. */ |
| +static bool |
| +create_directory_for_current_user (const char * path) |
| +{ |
| + PACL pACL = NULL; |
| + EXPLICIT_ACCESS ea; |
| + SECURITY_ATTRIBUTES sa; |
| + SECURITY_DESCRIPTOR SD; |
| + DWORD dwRes; |
| + bool result = true; |
| + TOKEN_USER *token_user = NULL; |
| + |
| + token_user = get_TOKEN_USER_current_user(); |
| + if (!token_user) |
| + return false; |
| + |
| + memset (&ea, 0, sizeof (EXPLICIT_ACCESS)); |
| + ea.grfAccessPermissions = GENERIC_ALL; /* Access to all. */ |
| + ea.grfAccessMode = SET_ACCESS; /* Set access and revoke everything else. */ |
| + /* This is necessary for the Windows Explorer GUI to show the correct tick |
| + boxes in the "Security" tab. */ |
| + ea.grfInheritance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; |
| + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; |
| + ea.Trustee.TrusteeType = TRUSTEE_IS_USER; |
| + ea.Trustee.ptstrName = (char*) token_user->User.Sid; |
| + |
| + /* Create a new ACL that contains the new ACEs. */ |
| + dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL); |
| + if (dwRes != ERROR_SUCCESS) |
| + return false; |
| + |
| + if (!InitializeSecurityDescriptor (&SD, |
| + SECURITY_DESCRIPTOR_REVISION)) |
| + goto cleanup; |
| + |
| + /* Add the ACL to the security descriptor. */ |
| + if (!SetSecurityDescriptorDacl (&SD, |
| + TRUE, /* use pACL */ |
| + pACL, |
| + FALSE)) /* not a default DACL */ |
| + goto cleanup; |
| + |
| + /* Initialize a security attributes structure. */ |
| + sa.nLength = sizeof (SECURITY_ATTRIBUTES); |
| + sa.lpSecurityDescriptor = &SD; |
| + sa.bInheritHandle = FALSE; |
| + |
| + /* Finally create the directory */ |
| + if (!CreateDirectoryA (path, &sa)) |
| + result = false; |
| + |
| + cleanup: |
| + if (pACL) |
| + LocalFree (pACL); |
| + |
| + if (token_user) |
| + delete[] (char*)token_user; |
| + |
| + return result; |
| +} |
| + |
| + |
| +char * |
| +win_mkdtemp (void) |
| +{ |
| + char lpTempPathBuffer[MAX_PATH]; |
| + |
| + /* Gets the temp path env string (no guarantee it's a valid path). */ |
| + DWORD dwRetVal = GetTempPath (MAX_PATH, lpTempPathBuffer); |
| + if (dwRetVal > MAX_PATH || (dwRetVal == 0)) |
| + { |
| + print_last_error (); |
| + return NULL; |
| + } |
| + |
| + /* Check that the directory actually exists. */ |
| + DWORD dwAttrib = GetFileAttributes (lpTempPathBuffer); |
| + bool temp_path_exists = (dwAttrib != INVALID_FILE_ATTRIBUTES |
| + && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); |
| + if (!temp_path_exists) |
| + { |
| + fprintf (stderr, "Path returned by GetTempPath does not exist: %s\n", |
| + lpTempPathBuffer); |
| + } |
| + |
| + /* Make sure there is enough space in the buffer for the prefix and random |
| + number.*/ |
| + int temp_path_buffer_len = dwRetVal; |
| + const int appended_len = strlen ("\\libgccjit-123456"); |
| + if (temp_path_buffer_len + appended_len + 1 >= MAX_PATH) |
| + { |
| + fprintf (stderr, "Temporary file path too long for generation of random" |
| + " directories: %s", lpTempPathBuffer); |
| + } |
| + |
| + /* This is all the space we have in the buffer to store the random number and |
| + prefix. */ |
| + int extraspace = MAX_PATH - temp_path_buffer_len - 1; |
| + |
| + int tries; |
| + const int max_tries = 1000; |
| + |
| + for (tries = 0; tries < max_tries; ++tries) |
| + { |
| + /* Get a random number in [0; UINT_MAX]. */ |
| + unsigned int rand_num; |
| + if (rand_s (&rand_num) != 0) |
| + { |
| + fprintf (stderr, |
| + "Failed to create a random number using rand_s(): %s\n", |
| + _strerror (NULL)); |
| + return NULL; |
| + } |
| + |
| + /* Create 6 digits random number. */ |
| + rand_num = ((double)rand_num / ((double) UINT_MAX + 1 ) * 1000000); |
| + |
| + /* Copy the prefix and random number to the buffer. */ |
| + snprintf (&lpTempPathBuffer[temp_path_buffer_len], extraspace, |
| + "\\libgccjit-%06u", rand_num); |
| + |
| + if (create_directory_for_current_user (lpTempPathBuffer)) |
| + break; // success! |
| + |
| + /* If we can't create the directory because we got unlucky and the |
| + directory already exists retry, otherwise fail. */ |
| + if (GetLastError () != ERROR_ALREADY_EXISTS) |
| + { |
| + print_last_error (); |
| + return NULL; |
| + } |
| + } |
| + |
| + if (tries == max_tries) |
| + { |
| + fprintf (stderr, "Failed to create a random directory in %s\n", |
| + lpTempPathBuffer); |
| + return NULL; |
| + } |
| + |
| + { |
| + int allocate_len = temp_path_buffer_len + appended_len + 1; |
| + char * result = XNEWVEC (char, allocate_len); |
| + strcpy (result, lpTempPathBuffer); |
| + return result; |
| + } |
| +} |
| +} |
| +} |
| diff --git a/gcc/jit/jit-w32.h b/gcc/jit/jit-w32.h |
| new file mode 100644 |
| index 00000000000..c6e30ea6de7 |
| --- /dev/null |
| +++ b/gcc/jit/jit-w32.h |
| @@ -0,0 +1,30 @@ |
| +/* Functions used by the Windows port of libgccjit. |
| + Copyright (C) 2020 Free Software Foundation, Inc. |
| + Contributed by Nicolas Bertolo <nicolasbertolo@gmail.com>. |
| + |
| +This file is part of GCC. |
| + |
| +GCC is free software; you can redistribute it and/or modify it |
| +under the terms of the GNU General Public License as published by |
| +the Free Software Foundation; either version 3, or (at your option) |
| +any later version. |
| + |
| +GCC is distributed in the hope that it will be useful, but |
| +WITHOUT ANY WARRANTY; without even the implied warranty of |
| +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| +General Public License for more details. |
| + |
| +You should have received a copy of the GNU General Public License |
| +along with GCC; see the file COPYING3. If not see |
| +<http://www.gnu.org/licenses/>. */ |
| + |
| +#include "config.h" |
| + |
| +#include <windows.h> |
| + |
| +namespace gcc { |
| +namespace jit { |
| +extern void print_last_error (void); |
| +extern char * win_mkdtemp(void); |
| +} |
| +} |
| -- |
| 2.25.1.windows.1 |
| |