From db55277b58cce460827bc77a90cc80c9639a6b6c Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Tue, 28 May 2019 20:45:39 -0400 Subject: [PATCH] Work on windows installer. We will probably shift to NSIS as the default installation method for windows. Shipping around a single binary just doesn't cut it if we want to be able to reliably use tools like `jpm` to build things. --- assets/icon.ico | Bin 0 -> 102134 bytes assets/icon_svg.svg | 11 ++ build_win.bat | 8 +- janet-installer.nsi | 181 ++++++++++++++++----- janet_win.rc | 1 + src/boot/boot.janet | 7 +- src/mainclient/init.janet | 1 + tools/EnvVarUpdate.nsh | 327 ++++++++++++++++++++++++++++++++++++++ tools/cook.janet | 27 ++-- tools/jpm | 7 +- tools/jpm.bat | 4 + 11 files changed, 514 insertions(+), 60 deletions(-) create mode 100644 assets/icon.ico create mode 100644 assets/icon_svg.svg create mode 100644 janet_win.rc create mode 100644 tools/EnvVarUpdate.nsh create mode 100644 tools/jpm.bat diff --git a/assets/icon.ico b/assets/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f15b21809fbedd96ae5f92041527ef038468086f GIT binary patch literal 102134 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 literal 0 HcmV?d00001 diff --git a/assets/icon_svg.svg b/assets/icon_svg.svg new file mode 100644 index 00000000..da52e33f --- /dev/null +++ b/assets/icon_svg.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/build_win.bat b/build_win.bat index ee33847b..e02c4894 100644 --- a/build_win.bat +++ b/build_win.bat @@ -53,7 +53,7 @@ for %%f in (src\boot\*.c) do ( ) %JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj @if errorlevel 1 goto :BUILDFAIL -build\janet_boot build\core_image.c JANET_PATH "C:/Janet/Library" +build\janet_boot build\core_image.c @rem Build the core image @%JANET_COMPILE% /Fobuild\core_image.obj build\core_image.c @@ -65,6 +65,9 @@ for %%f in (src\core\*.c) do ( @if errorlevel 1 goto :BUILDFAIL ) +@rem Build the resources +rc /nologo /fobuild\janet_win.res janet_win.rc + @rem Build the main client for %%f in (src\mainclient\*.c) do ( @%JANET_COMPILE% /Fobuild\mainclient\%%~nf.obj %%f @@ -72,7 +75,7 @@ for %%f in (src\mainclient\*.c) do ( ) @rem Link everything to main client -%JANET_LINK% /out:janet.exe build\core\*.obj build\mainclient\*.obj build\core_image.obj +%JANET_LINK% /out:janet.exe build\core\*.obj build\mainclient\*.obj build\core_image.obj build\janet_win.res @if errorlevel 1 goto :BUILDFAIL @rem Gen amlag @@ -132,6 +135,7 @@ copy src\include\janetconf.h dist\janetconf.h copy tools\cook.janet dist\cook.janet copy tools\highlight.janet dist\highlight.janet copy tools\jpm dist\jpm +copy tools\jpm.bat dist\jpm.bat exit /b 0 :TESTFAIL diff --git a/janet-installer.nsi b/janet-installer.nsi index 94a8e2f7..e34952b5 100644 --- a/janet-installer.nsi +++ b/janet-installer.nsi @@ -1,55 +1,162 @@ +# Use the modern UI !define MULTIUSER_EXECUTIONLEVEL Highest !define MULTIUSER_MUI !define MULTIUSER_INSTALLMODE_COMMANDLINE -!define MULTIUSER_INSTALLMODE_INSTDIR "janet" !include "MultiUser.nsh" !include "MUI2.nsh" - +!include ".\tools\EnvVarUpdate.nsh" + +# Basics Name "Janet" -OutFile "janet-install.exe" - -!define MUI_ABORTWARNING - +OutFile "janet-installer.exe" + +# Some Configuration +!define APPNAME "Janet" +!define DESCRIPTION "The Janet Programming Language" +!define HELPURL "http://janet-lang.org" + +# MUI Configuration +!define MUI_ICON "assets\icon.ico" +!define MUI_UNICON "assets\icon.ico" +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_BITMAP "assets\janet-w200.png" +!define MUI_HEADERIMAGE_RIGHT + +# Show a welcome page first !insertmacro MUI_PAGE_WELCOME + +# License page !insertmacro MUI_PAGE_LICENSE "LICENSE" -!insertmacro MUI_PAGE_COMPONENTS + +# Pick Install Directory !insertmacro MULTIUSER_PAGE_INSTALLMODE !insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES +page instfiles -!insertmacro MUI_PAGE_FINISH - -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - +# Need to set a language. !insertmacro MUI_LANGUAGE "English" -Section "Janet" BfWSection - SetOutPath $INSTDIR - File "janet.exe" - WriteUninstaller "$INSTDIR\janet-uninstall.exe" - - # Start Menu - CreateShortCut "$SMPROGRAMS\Janet.lnk" "$INSTDIR\janet.exe" "" "" -SectionEnd +function .onInit + setShellVarContext all +functionEnd -Function .onInit - !insertmacro MULTIUSER_INIT - !insertmacro MUI_LANGDLL_DISPLAY -FunctionEnd +section "install" + createDirectory "$INSTDIR\Library" + createDirectory "$INSTDIR\C" + createDirectory "$INSTDIR\bin" + setOutPath $INSTDIR + + file /oname=bin\janet.exe dist\janet.exe + file /oname=logo.ico assets\icon.ico + + file /oname=Library\cook.janet dist\cook.janet + + file /oname=C\janet.h dist\janet.h + file /oname=C\janetconf.h dist\janetconf.h + 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=bin\jpm.janet dist\jpm + file /oname=bin\jpm.bat dist\jpm.bat + + # Uninstaller - See function un.onInit and section "uninstall" for configuration + writeUninstaller "$INSTDIR\uninstall.exe" + + # Start Menu + createShortCut "$SMPROGRAMS\Janet.lnk" "$INSTDIR\janet.exe" "" "$INSTDIR\logo.ico" + + # HKLM (all users) vs HKCU (current user) + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_PATH "$INSTDIR\Library" + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_HEADERPATH "$INSTDIR\C" + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_BINDIR "$INSTDIR\bin" -!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${BfWSection} "The Janet programming language." -!insertmacro MUI_FUNCTION_DESCRIPTION_END + WriteRegExpandStr HKCU "Environment" JANET_PATH "$INSTDIR\Library" + WriteRegExpandStr HKCU "Environment" JANET_HEADERPATH "$INSTDIR\C" + WriteRegExpandStr HKCU "Environment" JANET_BINDIR "$INSTDIR\bin" + + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + # Update path + ${EnvVarUpdate} $0 "PATH" "A" "HKCU" "$INSTDIR\bin" ; Append + ${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR\bin" ; Append -Section "Uninstall" - Delete "$INSTDIR\janet.exe" - Delete "$INSTDIR\janet-uninstall.exe" - RMDir "$INSTDIR" -SectionEnd + # Registry information for add/remove programs + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "DisplayName" "Janet" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "UninstallString" "$INSTDIR\uninstall.exe" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "QuietUninstallString" "$INSTDIR\uninstall.exe /S" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "InstallLocation" "$INSTDIR" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "DisplayIcon" "$INSTDIR\logo.ico" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "Publisher" "Janet-Lang.org" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "HelpLink" "${HELPURL}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "URLUpdateInfo" "${HELPURL}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "URLInfoAbout" "${HELPURL}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "DisplayVersion" "0.6.0" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "VersionMajor" 0 + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "VersionMinor" 6 + # There is no option for modifying or repairing the install + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "NoModify" 1 + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "NoRepair" 1 + # Set the INSTALLSIZE constant (!defined at the top of this script) so Add/Remove Programs can accurately report the size + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" "EstimatedSize" 1000 +sectionEnd -Function un.onInit - !insertmacro MULTIUSER_UNINIT - !insertmacro MUI_UNGETLANGUAGE -FunctionEnd \ No newline at end of file +# Uninstaller + +function un.onInit + SetShellVarContext all + + #Verify the uninstaller - last chance to back out + MessageBox MB_OKCANCEL "Permanantly remove Janet?" IDOK next + Abort + next: +functionEnd + +section "uninstall" + + # Remove Start Menu launcher + delete "$SMPROGRAMS\Janet.lnk" + + # Remove files + delete $INSTDIR\logo.ico + + delete $INSTDIR\C\janet.c + delete $INSTDIR\C\janet.h + delete $INSTDIR\C\janet.lib + delete $INSTDIR\C\janet.exp + delete $INSTDIR\C\janetconf.h + + delete $INSTDIR\bin\jpm.janet + delete $INSTDIR\bin\jpm.bat + delete $INSTDIR\bin\janet.exe + + delete $INSTDIR\Library\cook.janet + + # Remove env vars + + DeleteRegValue HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_PATH + DeleteRegValue HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_HEADERPATH + DeleteRegValue HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" JANET_BINDIR + + DeleteRegValue HKCU "Environment" JANET_PATH + DeleteRegValue HKCU "Environment" JANET_HEADERPATH + DeleteRegValue HKCU "Environment" JANET_BINDIR + + # Unset PATH + ${un.EnvVarUpdate} $0 "PATH" "R" "HKCU" "$INSTDIR\bin" ; Remove + ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$INSTDIR\bin" ; Remove + + # make sure windows knows about the change + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + # Always delete uninstaller as the last action + delete $INSTDIR\uninstall.exe + + rmDir "$INSTDIR\Library" + rmDir "$INSTDIR\C" + rmDir "$INSTDIR\bin" + + # Remove uninstaller information from the registry + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet" +sectionEnd \ No newline at end of file diff --git a/janet_win.rc b/janet_win.rc new file mode 100644 index 00000000..5972ea36 --- /dev/null +++ b/janet_win.rc @@ -0,0 +1 @@ +IDI_MYICON ICON "assets\icon.ico" \ No newline at end of file diff --git a/src/boot/boot.janet b/src/boot/boot.janet index a491f9b5..862ec690 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -1605,13 +1605,14 @@ (var module/*syspath* "The path where globally installed libraries are located. The default is set at build time and is /usr/local/lib/janet on linux/posix, and - on Windows is C:/Janet/Library." + on Windows is the empty string." (or (process/opts "JANET_PATH") "")) (var module/*headerpath* "The path where the janet headers are installed. Useful for building - native modules or compiling code at runtime." - (process/opts "JANET_HEADERPATH")) + native modules or compiling code at runtime. Default on linux/posix is + /usr/local/include/janet, and on Windows is the empty string." + (or (process/opts "JANET_HEADERPATH") "")) # Version of fexists that works even with a reduced OS (if-let [has-stat (_env 'os/stat)] diff --git a/src/mainclient/init.janet b/src/mainclient/init.janet index c24eb62c..4b8b9281 100644 --- a/src/mainclient/init.janet +++ b/src/mainclient/init.janet @@ -12,6 +12,7 @@ (var *compile-only* false) (if-let [jp (os/getenv "JANET_PATH")] (set module/*syspath* jp)) + (if-let [jp (os/getenv "JANET_HEADERPATH")] (set module/*headerpath* jp)) # Flag handlers (def handlers :private diff --git a/tools/EnvVarUpdate.nsh b/tools/EnvVarUpdate.nsh new file mode 100644 index 00000000..80c12cd8 --- /dev/null +++ b/tools/EnvVarUpdate.nsh @@ -0,0 +1,327 @@ +/** + * EnvVarUpdate.nsh + * : Environmental Variables: append, prepend, and remove entries + * + * WARNING: If you use StrFunc.nsh header then include it before this file + * with all required definitions. This is to avoid conflicts + * + * Usage: + * ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString" + * + * Credits: + * Version 1.0 + * * Cal Turney (turnec2) + * * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this + * function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar, + * WriteEnvStr, and un.DeleteEnvStr + * * Diego Pedroso (deguix) for StrTok + * * Kevin English (kenglish_hi) for StrContains + * * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry + * (dandaman32) for StrReplace + * + * Version 1.1 (compatibility with StrFunc.nsh) + * * techtonik + * + * http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries + * + */ + + +!ifndef ENVVARUPDATE_FUNCTION +!define ENVVARUPDATE_FUNCTION +!verbose push +!verbose 3 +!include "LogicLib.nsh" +!include "WinMessages.NSH" +!include "StrFunc.nsh" + +; ---- Fix for conflict if StrFunc.nsh is already includes in main file ----------------------- +!macro _IncludeStrFunction StrFuncName + !ifndef ${StrFuncName}_INCLUDED + ${${StrFuncName}} + !endif + !ifndef Un${StrFuncName}_INCLUDED + ${Un${StrFuncName}} + !endif + !define un.${StrFuncName} "${Un${StrFuncName}}" +!macroend + +!insertmacro _IncludeStrFunction StrTok +!insertmacro _IncludeStrFunction StrStr +!insertmacro _IncludeStrFunction StrRep + +; ---------------------------------- Macro Definitions ---------------------------------------- +!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString + Push "${EnvVarName}" + Push "${Action}" + Push "${RegLoc}" + Push "${PathString}" + Call EnvVarUpdate + Pop "${ResultVar}" +!macroend +!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"' + +!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString + Push "${EnvVarName}" + Push "${Action}" + Push "${RegLoc}" + Push "${PathString}" + Call un.EnvVarUpdate + Pop "${ResultVar}" +!macroend +!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"' +; ---------------------------------- Macro Definitions end------------------------------------- + +;----------------------------------- EnvVarUpdate start---------------------------------------- +!define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' +!define hkcu_current_user 'HKCU "Environment"' + +!macro EnvVarUpdate UN + +Function ${UN}EnvVarUpdate + + Push $0 + Exch 4 + Exch $1 + Exch 3 + Exch $2 + Exch 2 + Exch $3 + Exch + Exch $4 + Push $5 + Push $6 + Push $7 + Push $8 + Push $9 + Push $R0 + + /* After this point: + ------------------------- + $0 = ResultVar (returned) + $1 = EnvVarName (input) + $2 = Action (input) + $3 = RegLoc (input) + $4 = PathString (input) + $5 = Orig EnvVar (read from registry) + $6 = Len of $0 (temp) + $7 = tempstr1 (temp) + $8 = Entry counter (temp) + $9 = tempstr2 (temp) + $R0 = tempChar (temp) */ + + ; Step 1: Read contents of EnvVarName from RegLoc + ; + ; Check for empty EnvVarName + ${If} $1 == "" + SetErrors + DetailPrint "ERROR: EnvVarName is blank" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Check for valid Action + ${If} $2 != "A" + ${AndIf} $2 != "P" + ${AndIf} $2 != "R" + SetErrors + DetailPrint "ERROR: Invalid Action - must be A, P, or R" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ${If} $3 == HKLM + ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5 + ${ElseIf} $3 == HKCU + ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5 + ${Else} + SetErrors + DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"' + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Check for empty PathString + ${If} $4 == "" + SetErrors + DetailPrint "ERROR: PathString is blank" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Make sure we've got some work to do + ${If} $5 == "" + ${AndIf} $2 == "R" + SetErrors + DetailPrint "$1 is empty - Nothing to remove" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Step 2: Scrub EnvVar + ; + StrCpy $0 $5 ; Copy the contents to $0 + ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or + ; after the last one are not removed here but instead in Step 3) + ${If} $0 != "" ; If EnvVar is not empty ... + ${Do} + ${${UN}StrStr} $7 $0 " ;" + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${${UN}StrRep} $0 $0 " ;" ";" ; Remove ';' + ${Loop} + ${Do} + ${${UN}StrStr} $7 $0 "; " + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${${UN}StrRep} $0 $0 "; " ";" ; Remove ';' + ${Loop} + ${Do} + ${${UN}StrStr} $7 $0 ";;" + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${${UN}StrRep} $0 $0 ";;" ";" + ${Loop} + + ; Remove a leading or trailing semicolon from EnvVar + StrCpy $7 $0 1 0 + ${If} $7 == ";" + StrCpy $0 $0 "" 1 ; Change ';' to '' + ${EndIf} + StrLen $6 $0 + IntOp $6 $6 - 1 + StrCpy $7 $0 1 $6 + ${If} $7 == ";" + StrCpy $0 $0 $6 ; Change ';' to '' + ${EndIf} + ; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug + ${EndIf} + + /* Step 3. Remove all instances of the target path/string (even if "A" or "P") + $6 = bool flag (1 = found and removed PathString) + $7 = a string (e.g. path) delimited by semicolon(s) + $8 = entry counter starting at 0 + $9 = copy of $0 + $R0 = tempChar */ + + ${If} $5 != "" ; If EnvVar is not empty ... + StrCpy $9 $0 + StrCpy $0 "" + StrCpy $8 0 + StrCpy $6 0 + + ${Do} + ${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter + + ${If} $7 == "" ; If we've run out of entries, + ${ExitDo} ; were done + ${EndIf} ; + + ; Remove leading and trailing spaces from this entry (critical step for Action=Remove) + ${Do} + StrCpy $R0 $7 1 + ${If} $R0 != " " + ${ExitDo} + ${EndIf} + StrCpy $7 $7 "" 1 ; Remove leading space + ${Loop} + ${Do} + StrCpy $R0 $7 1 -1 + ${If} $R0 != " " + ${ExitDo} + ${EndIf} + StrCpy $7 $7 -1 ; Remove trailing space + ${Loop} + ${If} $7 == $4 ; If string matches, remove it by not appending it + StrCpy $6 1 ; Set 'found' flag + ${ElseIf} $7 != $4 ; If string does NOT match + ${AndIf} $0 == "" ; and the 1st string being added to $0, + StrCpy $0 $7 ; copy it to $0 without a prepended semicolon + ${ElseIf} $7 != $4 ; If string does NOT match + ${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0, + StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon + ${EndIf} ; + + IntOp $8 $8 + 1 ; Bump counter + ${Loop} ; Check for duplicates until we run out of paths + ${EndIf} + + ; Step 4: Perform the requested Action + ; + ${If} $2 != "R" ; If Append or Prepend + ${If} $6 == 1 ; And if we found the target + DetailPrint "Target is already present in $1. It will be removed and" + ${EndIf} + ${If} $0 == "" ; If EnvVar is (now) empty + StrCpy $0 $4 ; just copy PathString to EnvVar + ${If} $6 == 0 ; If found flag is either 0 + ${OrIf} $6 == "" ; or blank (if EnvVarName is empty) + DetailPrint "$1 was empty and has been updated with the target" + ${EndIf} + ${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty), + StrCpy $0 $0;$4 ; append PathString + ${If} $6 == 1 + DetailPrint "appended to $1" + ${Else} + DetailPrint "Target was appended to $1" + ${EndIf} + ${Else} ; If Prepend (and EnvVar is not empty), + StrCpy $0 $4;$0 ; prepend PathString + ${If} $6 == 1 + DetailPrint "prepended to $1" + ${Else} + DetailPrint "Target was prepended to $1" + ${EndIf} + ${EndIf} + ${Else} ; If Action = Remove + ${If} $6 == 1 ; and we found the target + DetailPrint "Target was found and removed from $1" + ${Else} + DetailPrint "Target was NOT found in $1 (nothing to remove)" + ${EndIf} + ${If} $0 == "" + DetailPrint "$1 is now empty" + ${EndIf} + ${EndIf} + + ; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change + ; + ClearErrors + ${If} $3 == HKLM + WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section + ${ElseIf} $3 == HKCU + WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section + ${EndIf} + + IfErrors 0 +4 + MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3" + DetailPrint "Could not write updated $1 to $3" + Goto EnvVarUpdate_Restore_Vars + + ; "Export" our change + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + EnvVarUpdate_Restore_Vars: + ; + ; Restore the user's variables and return ResultVar + Pop $R0 + Pop $9 + Pop $8 + Pop $7 + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Push $0 ; Push my $0 (ResultVar) + Exch + Pop $0 ; Restore his $0 + +FunctionEnd + +!macroend ; EnvVarUpdate UN +!insertmacro EnvVarUpdate "" +!insertmacro EnvVarUpdate "un." +;----------------------------------- EnvVarUpdate end---------------------------------------- + +!verbose pop +!endif \ No newline at end of file diff --git a/tools/cook.janet b/tools/cook.janet index d9f63ecd..72bbaefd 100644 --- a/tools/cook.janet +++ b/tools/cook.janet @@ -111,21 +111,17 @@ # Configuration # -# Get default paths and options from environment -(def PREFIX (or (os/getenv "PREFIX") - (if is-win "C:\\Janet" "/usr/local"))) -(def BINDIR (or (os/getenv "BINDIR") - (string PREFIX sep "bin"))) -(def LIBDIR (or (os/getenv "LIBDIR") - (string PREFIX sep (if is-win "Library" "lib/janet")))) -(def INCLUDEDIR (or (os/getenv "INCLUDEDIR") - module/*headerpath* - (string PREFIX sep "include" sep "janet"))) +# Installation settings +(def BINDIR (os/getenv "JANET_BINDIR")) +(def LIBDIR (or (os/getenv "JANET_PATH") module/*syspath*)) +(def INCLUDEDIR (or (os/getenv "JANET_HEADERPATH") module/*headerpath*)) + +# Compilation settings (def OPTIMIZE (or (os/getenv "OPTIMIZE") 2)) (def CC (or (os/getenv "CC") (if is-win "cl" "cc"))) (def LD (or (os/getenv "LINKER") (if is-win "link" CC))) (def LDFLAGS (or (os/getenv "LFLAGS") - (if is-win "" + (if is-win " /nologo" (string " -shared" (if is-mac " -undefined dynamic_lookup" ""))))) (def CFLAGS (or (os/getenv "CFLAGS") (if is-win "" " -std=c99 -Wall -Wextra -fpic"))) @@ -134,7 +130,10 @@ "Get an option, allowing overrides via dynamic bindings AND some default value dflt if no dynamic binding is set." [opts key dflt] - (or (opts key) (dyn key dflt))) + (def ret (or (opts key) (dyn key dflt))) + (if (= nil ret) + (error (string "option :" key " not set"))) + ret) # # OS and shell helpers @@ -162,7 +161,7 @@ (defn copy "Copy a file or directory recursively from one location to another." [src dest] - (shell (if is-win "robocopy " "cp -rf ") src " " dest (if is-win " /s /e" ""))) + (shell (if is-win "xcopy " "cp -rf ") src " " dest (if is-win " /h /y /t /e" ""))) # # C Compilation @@ -247,7 +246,7 @@ (def olist (string/join objects " ")) (rule target objects (if is-win - (shell ld " " lflags " /DLL /OUT:" target " " olist " %JANET_PATH%\\janet.lib") + (shell ld " " lflags " /DLL /OUT:" target " " olist " " (opt opts :includedir INCLUDEDIR) "\\janet.lib") (shell ld " " cflags " -o " target " " olist " " lflags)))) (defn- create-buffer-c diff --git a/tools/jpm b/tools/jpm index a612cc2a..3497b80d 100755 --- a/tools/jpm +++ b/tools/jpm @@ -19,10 +19,9 @@ (print ` Keys are: - --prefix : The prefix to install to. Defaults to $PREFIX or /usr/local - --libdir : The directory to install. Defaults to $LIBDIR or $prefix/lib/janet - --includedir : The directory containing janet headers. Defaults to $INCLUDEDIR or module/*headerpath*. - --bindir : The directory to install binaries and scripts. Defaults to $BINDIR or $prefix/bin + --libdir : The directory to install modules to. Defaults to $JANET_PATH or module/*syspath* + --includedir : The directory containing janet headers. Defaults to $JANET_HEADERPATH or module/*headerpath* + --bindir : The directory to install binaries and scripts. Defaults to $JANET_BINDIR. --optimize : Optimization level for natives. Defaults to $OPTIMIZE or 2. --compiler : C compiler to use for natives. Defaults to $CC or cc. --linker : C linker to use for linking natives. Defaults to $LINKER or cc. diff --git a/tools/jpm.bat b/tools/jpm.bat new file mode 100644 index 00000000..a595a1e0 --- /dev/null +++ b/tools/jpm.bat @@ -0,0 +1,4 @@ +@echo off +@rem Wrapper arounf jpm + +janet %~dp0\jpm.janet %*