diff --git a/appveyor.yml b/appveyor.yml index f5911540..4f9fd582 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,11 +18,8 @@ init: - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" install: - - build_win - - build_win test - choco install nsis -y -pre - - build_win dist - + - build_win all build: off only_commits: @@ -31,7 +28,7 @@ only_commits: - src/ artifacts: - - path: janet-installer.exe + - path: janet-v1.2.0-windows-installer.exe name: janet-v1.2.0-windows-installer.exe type: File diff --git a/auxlib/cook.janet b/auxlib/cook.janet index 5ff11b70..09d08711 100644 --- a/auxlib/cook.janet +++ b/auxlib/cook.janet @@ -113,7 +113,7 @@ (def default-compiler (if is-win "cl" "cc")) (def default-linker (if is-win "link" "cc")) -(def default-archiver (if is-win "link" "ar")) +(def default-archiver (if is-win "lib" "ar")) # Default flags for natives, but not required (def default-lflags (if is-win ["/nologo"] [])) @@ -277,7 +277,7 @@ (error "cannot find libpath: provide --libpath or JANET_LIBPATH")) (string (dyn :libpath JANET_LIBPATH) sep - "libjanet.a")) + (if is-win "libjanet.lib" "libjanet.a"))) (defn- win-import-library "On windows, an import library is needed to link to a dll statically." @@ -314,7 +314,7 @@ (rule target objects (print "creating static library " target "...") (if is-win - (shell ar "/lib" "/nologo" (string "/out:" target) ;objects) + (shell ar "/nologo" (string "/out:" target) ;objects) (shell ar "rcs" target ;objects)))) (defn- create-buffer-c-impl @@ -456,9 +456,9 @@ int main(int argc, const char **argv) { (try (rm path) ([err] (unless (= err "No such file or directory") (error err))))) + (:close f) (print "removing " manifest) (rm manifest) - (:close f) (print "Uninstalled.")) (defn clear-cache diff --git a/build_win.bat b/build_win.bat index 14dd1961..e8d41c29 100644 --- a/build_win.bat +++ b/build_win.bat @@ -14,10 +14,12 @@ @if "%1"=="test" goto TEST @if "%1"=="dist" goto DIST @if "%1"=="install" goto INSTALL +@if "%1"=="test-install" goto TESTINSTALL +@if "%1"=="all" goto ALL @rem Set compile and link options here @setlocal -@set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /LD /D_CRT_SECURE_NO_WARNINGS +@set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS @set JANET_LINK=link /nologo @set JANET_LINK_STATIC=lib /nologo @@ -81,12 +83,8 @@ for %%f in (src\mainclient\*.c) do ( @if errorlevel 1 goto :BUILDFAIL @rem Build static library (libjanet.a) -@rem %JANET_LINK_STATIC% /out:build\libjanet.a build\core\*.obj build\core_image.obj -@rem @if errorlevel 1 goto :BUILDFAIL - -@rem Build dynamic library (janet.dll) -@rem %JANET_LINK% /out:build\janet.dll /dll build\core\*.obj build\core_image.obj -@rem @if errorlevel 1 goto :BUILDFAIL +%JANET_LINK_STATIC% /out:build\libjanet.lib build\core\*.obj build\core_image.obj +@if errorlevel 1 goto :BUILDFAIL @rem Gen amlag setlocal enabledelayedexpansion @@ -94,7 +92,7 @@ set "amalg_files=" for %%f in (src\core\*.c) do ( set "amalg_files=!amalg_files! %%f" ) -build\janet.exe tools\amalg.janet src\core\util.h src\core\state.h src\core\gc.h src\core\vector.h src\core\fiber.h src\core\regalloc.h src\core\compile.h src\core\emit.h src\core\symcache.h %amalg_files% build\core_image.c > build\janet.c +janet.exe tools\amalg.janet src\core\util.h src\core\state.h src\core\gc.h src\core\vector.h src\core\fiber.h src\core\regalloc.h src\core\compile.h src\core\emit.h src\core\symcache.h %amalg_files% build\core_image.c > build\janet.c echo === Successfully built janet.exe for Windows === echo === Run 'build_win test' to run tests. == @@ -126,7 +124,7 @@ exit /b 0 :TEST for %%f in (test/suite*.janet) do ( janet.exe test\%%f - @if errorlevel 1 goto :TESTFAIL + @if errorlevel 1 goto TESTFAIL ) exit /b 0 @@ -145,9 +143,7 @@ copy janet.exp dist\janet.exp copy src\include\janet.h dist\janet.h copy src\conf\janetconf.h dist\janetconf.h - -@rem copy build\janet.dll dist\janet.dll -@rem copy build\libjanet.a dist\libjanet.a +copy build\libjanet.lib dist\libjanet.lib copy auxlib\cook.janet dist\cook.janet copy auxlib\path.janet dist\path.janet @@ -159,13 +155,39 @@ copy tools\jpm.bat dist\jpm.bat "C:\Program Files (x86)\NSIS\makensis.exe" janet-installer.nsi exit /b 0 -:INSTALL @rem Run the installer. (Installs to the local user with default settings) +:INSTALL +@echo Running Installer... FOR %%a in (janet-*-windows-installer.exe) DO ( %%a /S /D=%userprofile%\AppData\Local\Janet\ ) exit /b 0 +@rem Test the installation. +:TESTINSTALL +pushd test\install +call jpm clean +@if errorlevel 1 goto :TESTFAIL +call jpm test +@if errorlevel 1 goto :TESTFAIL +popd +exit /b 0 + +@rem build, test, dist, install. Useful for local dev. +:ALL +call %0 build +@if errorlevel 1 exit /b 1 +call %0 test +@if errorlevel 1 exit /b 1 +call %0 dist +@if errorlevel 1 exit /b 1 +call %0 install +@if errorlevel 1 exit /b 1 +call %0 test-install +@if errorlevel 1 exit /b 1 +@echo Done! +exit /b 0 + :TESTFAIL @echo. @echo ******************************************************* diff --git a/janet-installer.nsi b/janet-installer.nsi index 17b070ca..2278bb5e 100644 --- a/janet-installer.nsi +++ b/janet-installer.nsi @@ -20,6 +20,7 @@ VIFileVersion "${PRODUCT_VERSION}" !include "MUI2.nsh" !include ".\tools\EnvVarUpdate.nsh" !include "LogicLib.nsh" +!include "./tools\FileAssociation.nsh" # Basics Name "Janet" @@ -99,8 +100,7 @@ section "Janet" BfWSection file /oname=C\janet.lib dist\janet.lib file /oname=C\janet.exp dist\janet.exp file /oname=C\janet.c dist\janet.c - #file /oname=C\janet.dll dist\janet.dll - #file /oname=C\libjanet.a dist\libjanet.a + file /oname=C\libjanet.lib dist\libjanet.lib # Documentation file /oname=docs\docs.html dist\doc.html @@ -126,6 +126,9 @@ section "Janet" BfWSection # Update path ${EnvVarUpdate} $0 "PATH" "A" "HKCU" "$INSTDIR\bin" ; Append ${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR\bin" ; Append + + # File Assocations + ${RegisterExtension} "$INSTDIR\bin\janet.exe" ".janet" "Janet Source File" # Registry information for add/remove programs WriteRegStr SHCTX "${UNINST_KEY}" "DisplayName" "Janet" @@ -174,6 +177,9 @@ section "uninstall" # Unset PATH ${un.EnvVarUpdate} $0 "PATH" "R" "HKCU" "$INSTDIR\bin" ; Remove ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$INSTDIR\bin" ; Remove + + # File Associations + ${UnRegisterExtension} ".janet" "Janet Source File" # make sure windows knows about the change SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 diff --git a/src/core/corelib.c b/src/core/corelib.c index 55a5b8f2..f7faea2e 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -45,7 +45,14 @@ typedef int Clib; typedef HINSTANCE Clib; #define load_clib(name) LoadLibrary((name)) #define symbol_clib(lib, sym) GetProcAddress((lib), (sym)) -#define error_clib() "could not load dynamic library" +static char error_clib_buf[256]; +static char *error_clib(void) { + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + error_clib_buf, sizeof(error_clib_buf), NULL); + error_clib_buf[strlen(error_clib_buf) - 1] = '\0'; + return error_clib_buf; +} #else #include typedef void *Clib; diff --git a/src/mainclient/main.c b/src/mainclient/main.c index baed5a79..dd862eb4 100644 --- a/src/mainclient/main.c +++ b/src/mainclient/main.c @@ -25,6 +25,7 @@ #ifdef _WIN32 #include +#include #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif @@ -38,14 +39,33 @@ int main(int argc, char **argv) { JanetArray *args; JanetTable *env; - /* Enable color console on windows 10 console and utf8 output. */ #ifdef _WIN32 + /* Enable color console on windows 10 console and utf8 output. */ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwMode = 0; GetConsoleMode(hOut, &dwMode); dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; SetConsoleMode(hOut, dwMode); SetConsoleOutputCP(65001); + + /* Add directory containing janet.exe as DLL search path for + dynamic modules on windows. This is needed because dynamic modules reference + janet.exe for symbols. Otherwise, janet.exe would have to be in the current directory + to load natives correctly. */ + #ifndef JANET_NO_DYNAMIC_MODULES + { + SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_USER_DIRS); + HMODULE hModule = GetModuleHandleW(NULL); + wchar_t path[MAX_PATH]; + GetModuleFileNameW(hModule, path, MAX_PATH); + size_t i = wcsnlen(path, MAX_PATH); + while (i > 0 && path[i] != '\\') + path[i--] = '\0'; + if (i) AddDllDirectory(path); + GetCurrentDirectoryW(MAX_PATH, path); + AddDllDirectory(path); + } +#endif #endif /* Set up VM */ @@ -67,7 +87,7 @@ int main(int argc, char **argv) { /* Save current executable path to (dyn :executable) */ janet_table_put(env, janet_ckeywordv("executable"), janet_cstringv(argv[0])); - + /* Run startup script */ status = janet_dobytes(env, janet_gen_init, janet_gen_init_size, "init.janet", NULL); diff --git a/tools/FileAssociation.nsh b/tools/FileAssociation.nsh new file mode 100644 index 00000000..71a9162e --- /dev/null +++ b/tools/FileAssociation.nsh @@ -0,0 +1,190 @@ +/* +_____________________________________________________________________________ + + File Association +_____________________________________________________________________________ + + Based on code taken from http://nsis.sourceforge.net/File_Association + + Usage in script: + 1. !include "FileAssociation.nsh" + 2. [Section|Function] + ${FileAssociationFunction} "Param1" "Param2" "..." $var + [SectionEnd|FunctionEnd] + + FileAssociationFunction=[RegisterExtension|UnRegisterExtension] + +_____________________________________________________________________________ + + ${RegisterExtension} "[executable]" "[extension]" "[description]" + +"[executable]" ; executable which opens the file format + ; +"[extension]" ; extension, which represents the file format to open + ; +"[description]" ; description for the extension. This will be display in Windows Explorer. + ; + + + ${UnRegisterExtension} "[extension]" "[description]" + +"[extension]" ; extension, which represents the file format to open + ; +"[description]" ; description for the extension. This will be display in Windows Explorer. + ; + +_____________________________________________________________________________ + + Macros +_____________________________________________________________________________ + + Change log window verbosity (default: 3=no script) + + Example: + !include "FileAssociation.nsh" + !insertmacro RegisterExtension + ${FileAssociation_VERBOSE} 4 # all verbosity + !insertmacro UnRegisterExtension + ${FileAssociation_VERBOSE} 3 # no script +*/ + + +!ifndef FileAssociation_INCLUDED +!define FileAssociation_INCLUDED + +!include Util.nsh + +!verbose push +!verbose 3 +!ifndef _FileAssociation_VERBOSE + !define _FileAssociation_VERBOSE 3 +!endif +!verbose ${_FileAssociation_VERBOSE} +!define FileAssociation_VERBOSE `!insertmacro FileAssociation_VERBOSE` +!verbose pop + +!macro FileAssociation_VERBOSE _VERBOSE + !verbose push + !verbose 3 + !undef _FileAssociation_VERBOSE + !define _FileAssociation_VERBOSE ${_VERBOSE} + !verbose pop +!macroend + + + +!macro RegisterExtensionCall _EXECUTABLE _EXTENSION _DESCRIPTION + !verbose push + !verbose ${_FileAssociation_VERBOSE} + Push `${_DESCRIPTION}` + Push `${_EXTENSION}` + Push `${_EXECUTABLE}` + ${CallArtificialFunction} RegisterExtension_ + !verbose pop +!macroend + +!macro UnRegisterExtensionCall _EXTENSION _DESCRIPTION + !verbose push + !verbose ${_FileAssociation_VERBOSE} + Push `${_EXTENSION}` + Push `${_DESCRIPTION}` + ${CallArtificialFunction} UnRegisterExtension_ + !verbose pop +!macroend + + + +!define RegisterExtension `!insertmacro RegisterExtensionCall` +!define un.RegisterExtension `!insertmacro RegisterExtensionCall` + +!macro RegisterExtension +!macroend + +!macro un.RegisterExtension +!macroend + +!macro RegisterExtension_ + !verbose push + !verbose ${_FileAssociation_VERBOSE} + + Exch $R2 ;exe + Exch + Exch $R1 ;ext + Exch + Exch 2 + Exch $R0 ;desc + Exch 2 + Push $0 + Push $1 + + ReadRegStr $1 HKCR $R1 "" ; read current file association + StrCmp "$1" "" NoBackup ; is it empty + StrCmp "$1" "$R0" NoBackup ; is it our own + WriteRegStr HKCR $R1 "backup_val" "$1" ; backup current value +NoBackup: + WriteRegStr HKCR $R1 "" "$R0" ; set our file association + + ReadRegStr $0 HKCR $R0 "" + StrCmp $0 "" 0 Skip + WriteRegStr HKCR "$R0" "" "$R0" + WriteRegStr HKCR "$R0\shell" "" "open" + WriteRegStr HKCR "$R0\DefaultIcon" "" "$R2,0" +Skip: + WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"' + WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0" + WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"' + + Pop $1 + Pop $0 + Pop $R2 + Pop $R1 + Pop $R0 + + !verbose pop +!macroend + + + +!define UnRegisterExtension `!insertmacro UnRegisterExtensionCall` +!define un.UnRegisterExtension `!insertmacro UnRegisterExtensionCall` + +!macro UnRegisterExtension +!macroend + +!macro un.UnRegisterExtension +!macroend + +!macro UnRegisterExtension_ + !verbose push + !verbose ${_FileAssociation_VERBOSE} + + Exch $R1 ;desc + Exch + Exch $R0 ;ext + Exch + Push $0 + Push $1 + + ReadRegStr $1 HKCR $R0 "" + StrCmp $1 $R1 0 NoOwn ; only do this if we own it + ReadRegStr $1 HKCR $R0 "backup_val" + StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key + DeleteRegKey HKCR $R0 + Goto NoOwn + +Restore: + WriteRegStr HKCR $R0 "" $1 + DeleteRegValue HKCR $R0 "backup_val" + DeleteRegKey HKCR $R1 ;Delete key with association name settings + +NoOwn: + + Pop $1 + Pop $0 + Pop $R1 + Pop $R0 + + !verbose pop +!macroend + +!endif # !FileAssociation_INCLUDED