From: Nicolás Bértolo Date: Fri, 22 May 2020 20:54:41 +0000 (-0300) Subject: jit: port libgccjit to Windows X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c83027f32d9cca84959c7d6a1e519a0129731501;p=gcc.git jit: port libgccjit to Windows 2020-05-28 Nicolas Bértolo /ChangeLog: * configure.ac: Don't require --enable-host-shared when building for Mingw. * configure: Regenerate. 2020-05-28 Nicolas Bértolo 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 gcc/c/ChangeLog: * Make-lang.in: Remove extra slash. 2020-05-28 Nicolas Bértolo 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(). --- 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 +#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 . + +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 +. */ + +#include "config.h" + +/* Required for rand_s */ +#define _CRT_RAND_S + +#include +#include + +#include "jit-w32.h" + +#include "libiberty.h" + +#include +#include + +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(&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 . + +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 +. */ + +#include "config.h" + +#include + +namespace gcc { +namespace jit { +extern void print_last_error (void); +extern char * win_mkdtemp(void); +} +}