diff options
author | Ian Lynagh <igloo@earth.li> | 2013-05-12 01:44:02 +0100 |
---|---|---|
committer | Ian Lynagh <igloo@earth.li> | 2013-05-12 20:25:10 +0100 |
commit | b35a6ce0e34255d200ddcf341ffc645fd237ea32 (patch) | |
tree | 438810e43039e69db6af11711190b1ea0d399ef9 /driver | |
parent | b2cae55fdd2b4b331bd609380b2667904d8a2eda (diff) | |
download | haskell-b35a6ce0e34255d200ddcf341ffc645fd237ea32.tar.gz |
More work towards dynamic programs on Windows
Dynamic GHC is now working in-place, but pathologically slow due
to the DLL split.
(GHC assumes that all intra-package calls are in the same DLL, but that
isn't true when we split the GHC package into 2 DLLs. That means that
GHC's startup time is around 22 seconds, as it is doing run-time
linking).
Also, ghci isn't actually working yet:
$ inplace/bin/ghc-stage2 --interactive
GHCi, version 7.7.20130512: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... <command line>: can't load .so/.DLL for:
HSghc-prim-0.3.1.0.dll (addDLL: could not load DLL)
ghc-stage2.exe: HSghc-prim-0.3.1.0: The specified module could not be
found.
Diffstat (limited to 'driver')
-rw-r--r-- | driver/utils/dynwrapper.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/driver/utils/dynwrapper.c b/driver/utils/dynwrapper.c new file mode 100644 index 0000000000..eead8bd0a0 --- /dev/null +++ b/driver/utils/dynwrapper.c @@ -0,0 +1,197 @@ + +/* +Need to concatenate this file with something that defines: +LPTSTR path_dirs[]; +LPTSTR progDll; +LPTSTR rtsDll; +*/ + +#include <stdarg.h> +#include <stdio.h> +#include <Windows.h> +#include <Shlwapi.h> + +#include "Rts.h" + +void die(char *fmt, ...) { + va_list argp; + + fprintf(stderr, "error: "); + va_start(argp, fmt); + vfprintf(stderr, fmt, argp); + va_end(argp); + fprintf(stderr, "\n"); + + exit(1); +} + +LPTSTR getModuleFileName(void) { + HMODULE hExe; + LPTSTR exePath; + DWORD exePathSize; + DWORD res; + + hExe = GetModuleHandle(NULL); + if (hExe == NULL) { + die("GetModuleHandle failed"); + } + + // 300 chars ought to be enough, but there are various cases where + // it might not be (e.g. unicode paths, or \\server\foo\... paths. + // So we start off with 300 and grow if necessary. + exePathSize = 300; + exePath = malloc(exePathSize); + if (exePath == NULL) { + die("Mallocing %d for GetModuleFileName failed", exePathSize); + } + + while ((res = GetModuleFileName(hExe, exePath, exePathSize)) && + (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { + exePathSize *= 2; + exePath = realloc(exePath, exePathSize); + if (exePath == NULL) { + die("Reallocing %d for GetModuleFileName failed", exePathSize); + } + } + + if (!res) { + die("GetModuleFileName failed"); + } + return exePath; +} + +void setPath(void) { + LPTSTR *dir; + LPTSTR path; + int n; + int len = 0; + LPTSTR exePath, s; + + exePath = getModuleFileName(); + for(s = exePath; *s != '\0'; s++) { + if (*s == '\\') { + *s = '/'; + } + } + s = StrRChr(exePath, NULL, '/'); + if (s == NULL) { + die("No directory separator in executable path: %s", exePath); + } + s[0] = '\0'; + n = s - exePath; + + for (dir = path_dirs; *dir != NULL; dir++) { + len += n + 7/* /../../ */ + lstrlen(*dir) + 1/* semicolon */; + } + len++; // NUL + + path = malloc(len); + if (path == NULL) { + die("Mallocing %d for PATH failed", len); + } + s = path; + for (dir = path_dirs; *dir != NULL; dir++) { + StrCpy(s, exePath); + s += n; + StrCpy(s, "/../../"); + s += 7; + StrCpy(s, *dir); + s += lstrlen(*dir); + s[0] = ';'; + s++; + } + s[0] = '\0'; + free(exePath); + + if (! SetEnvironmentVariable(TEXT("PATH"), path)) { + printf("SetEnvironmentVariable failed (%d)\n", GetLastError()); + } + free(path); +} + +HINSTANCE loadDll(LPTSTR dll) { + HINSTANCE h; + DWORD dw; + LPVOID lpMsgBuf; + + h = LoadLibrary(dll); + + if (h == NULL) { + dw = GetLastError(); + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL ); + die("loadDll %s failed: %d: %s\n", dll, dw, lpMsgBuf); + } + + return h; +} + +void *GetNonNullProcAddress(HINSTANCE h, char *sym) { + void *p; + + p = GetProcAddress(h, sym); + if (p == NULL) { + die("Failed to find address for %s", sym); + } + return p; +} + +HINSTANCE GetNonNullModuleHandle(LPTSTR dll) { + HINSTANCE h; + + h = GetModuleHandle(dll); + if (h == NULL) { + die("Failed to get module handle for %s", dll); + } + return h; +} + +typedef int (*hs_main_t)(int , char **, StgClosure *, RtsConfig); + +int main(int argc, char *argv[]) { + void *p; + HINSTANCE hRtsDll, hProgDll; + LPTSTR oldPath; + + StgClosure *main_p; + RtsConfig *rts_config_p; + hs_main_t hs_main_p; + + // MSDN says: An environment variable has a maximum size limit of + // 32,767 characters, including the null-terminating character. + oldPath = malloc(32767); + if (oldPath == NULL) { + die("Mallocing 32767 for oldPath failed"); + } + + if (!GetEnvironmentVariable(TEXT("PATH"), oldPath, 32767)) { + if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) { + oldPath[0] = '\0'; + } + else { + die("Looking up PATH env var failed"); + } + } + setPath(); + hProgDll = loadDll(progDll); + if (! SetEnvironmentVariable(TEXT("PATH"), oldPath)) { + printf("SetEnvironmentVariable failed (%d)\n", GetLastError()); + } + free(oldPath); + + hRtsDll = GetNonNullModuleHandle(rtsDll); + + hs_main_p = GetNonNullProcAddress(hRtsDll, "hs_main"); + rts_config_p = GetNonNullProcAddress(hRtsDll, "defaultRtsConfig"); + main_p = GetNonNullProcAddress(hProgDll, "ZCMain_main_closure"); + + return hs_main_p(argc, argv, main_p, *rts_config_p); +} + |