1
0
mirror of https://github.com/janet-lang/janet synced 2025-11-21 01:34:49 +00:00

Compare commits

..

36 Commits

Author SHA1 Message Date
Calvin Rose
26513a7a16 Update changelog 2019-05-30 19:33:09 -04:00
Calvin Rose
d005ac6888 Appease MSVC. 2019-05-30 19:21:11 -04:00
Calvin Rose
7fdb098a20 Add process.h. 2019-05-30 19:14:54 -04:00
Calvin Rose
a4a200e037 Spawn.h not found in windows. 2019-05-30 19:13:13 -04:00
Calvin Rose
15d95d8803 Windows include issue. 2019-05-30 18:50:52 -04:00
Calvin Rose
46950a8cb3 Convert os/execute to use posix_spawn. 2019-05-30 18:40:10 -04:00
Calvin Rose
4867cab569 Correct changelog date. 2019-05-29 22:21:06 -04:00
Calvin Rose
c8cf7c2445 Appease MSVC. 2019-05-29 22:12:24 -04:00
Calvin Rose
1b63215aad Remove extra functions. 2019-05-29 22:00:47 -04:00
Calvin Rose
bcbe42ab23 Add API version checking for modules.
Checking now actively implemented for dynamic modules
in a fully backwards compatible way.
2019-05-29 21:58:20 -04:00
Calvin Rose
c8c6419013 Update installer again. 2019-05-29 19:48:31 -04:00
Calvin Rose
e8516c29e0 Update installer and jpm to work better on windows. 2019-05-29 19:01:12 -04:00
Calvin Rose
12247bd958 Update installer. 2019-05-29 17:48:46 -04:00
Calvin Rose
9d30d5f6e3 Update installer. 2019-05-29 13:02:15 -04:00
Calvin Rose
ba0956488d Prepare for 0.6.0 release 2019-05-29 12:19:39 -04:00
Calvin Rose
31f502b508 Add more to util.h to help with amalg build. 2019-05-29 12:07:53 -04:00
Calvin Rose
efaaead378 Update changelog 2019-05-29 11:58:41 -04:00
Calvin Rose
4d47d92a4a Windows WEXITSTATUS fix? 2019-05-29 11:53:57 -04:00
Calvin Rose
b39ad97a87 Fix up close to return proper exit code. 2019-05-29 11:50:46 -04:00
Calvin Rose
af23040d9c file/close returns an integer.
If opened with popen, returns the exit code. Otherwise
returns nil.
2019-05-29 11:40:58 -04:00
Calvin Rose
fd2d706e33 Add os/remove. 2019-05-29 11:31:19 -04:00
Calvin Rose
178d175bcf Update options for jpm and path stuff. 2019-05-29 11:04:38 -04:00
Calvin Rose
7a7f586094 Merge branch 'master' of github.com:janet-lang/janet 2019-05-28 23:03:08 -04:00
Calvin Rose
5124587c96 Merge pull request #114 from andrewchambers/configcheck
Add api for checking build compatibilty.
2019-05-28 23:02:08 -04:00
Calvin Rose
6c897b1a37 Add default for bindir. 2019-05-28 22:41:47 -04:00
Calvin Rose
c6ac53f4be Try distributing only the installer. 2019-05-28 21:05:47 -04:00
Calvin Rose
2d7812a06c Update appveyor.yml 2019-05-28 20:52:36 -04:00
Calvin Rose
db55277b58 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.
2019-05-28 20:45:39 -04:00
Calvin Rose
75818217a6 Update CI tasks. 2019-05-28 14:02:45 -04:00
Calvin Rose
486b80fa7b Update changelog, change version to 0.6.0 2019-05-28 13:59:12 -04:00
Calvin Rose
873054d055 Update CI test-install. 2019-05-28 13:03:47 -04:00
Calvin Rose
f12f896020 Change test-install 2019-05-28 12:59:21 -04:00
Calvin Rose
09ab391d13 Add import-rules to cook.
First steps to recursive rules. Just needs normalized paths
relative to the directory of the imported file.
2019-05-28 09:49:10 -04:00
Calvin Rose
7569930b0c More work on cook and jpm. 2019-05-28 08:48:35 -04:00
Calvin Rose
e7189438dd More work on jpm
Switch to rea dependency graph for a rake-like tool.
This model is more powerful for writing build scripts.
2019-05-27 22:14:24 -04:00
Calvin Rose
1696de233c Add jpm tool, based on cook.
Modify cook as well.
2019-05-27 16:50:57 -04:00
26 changed files with 1076 additions and 279 deletions

View File

@@ -1,12 +1,11 @@
image: freebsd/latest
packages:
- gmake
- gcc
tasks:
- build: |
cd janet
gmake CC=gcc
gmake test CC=gcc
sudo gmake install CC=gcc
gmake test-install CC=gcc
gmake test-amalg CC=gcc
gmake
gmake test
sudo gmake install
gmake test-install
gmake test-amalg

View File

@@ -1,8 +1,17 @@
# Changelog
All notable changes to this project will be documented in this file.
## 1.0.0 - ??
## Unreleased
- Add API compatibility checking for modules. This will let native modules not load
when the host program is not of a compatible version or configuration.
- Change signature of `os/execute` to be much more flexible.
## 0.6.0 - 2019-05-29
- `file/close` returns exit code when closing file opened with `file/popen`.
- Add `os/rename`
- Update windows installer to include tools like `jpm`.
- Add `jpm` tool for building and managing projects.
- Change interface to `cook` tool.
- Add optional filters to `module/paths` to further refine import methods.
- Add keyword arguments via `&keys` in parameter list.
- Add `-k` flag for flychecking source.
@@ -79,7 +88,7 @@ All notable changes to this project will be documented in this file.
- Disallow NaNs as table or struct keys
- Update module resolution paths and format
## 0.3.0 - 2019-26-01
## 0.3.0 - 2019-01-26
- Add amalgamated build to janet for easier embedding.
- Add os/date function
- Add slurp and spit to core library.

View File

@@ -300,6 +300,7 @@ install: $(JANET_TARGET) $(PKG_CONFIG_PATH)/janet.pc
ln -sf $(SONAME) $(LIBDIR)/libjanet.so
ln -sf libjanet.so.$(shell $(JANET_TARGET) -e '(print janet/version)') $(LIBDIR)/$(SONAME)
cp tools/cook.janet $(JANET_PATH)
cp tools/jpm $(BINDIR)/jpm
cp tools/highlight.janet $(JANET_PATH)
cp tools/bars.janet $(JANET_PATH)
mkdir -p $(MANPATH)
@@ -321,7 +322,7 @@ clean:
-rm -rf build vgcore.* callgrind.*
test-install:
cd test/install && rm -rf build && janet build && janet build
cd test/install && rm -rf build && jpm build && jpm test
build/embed_janet.o: build/janet.c $(JANET_HEADERS)
$(CC) $(CFLAGS) -c $< -o $@

View File

@@ -21,9 +21,8 @@ install:
- build_win
- build_win test
- choco install nsis -y -pre
- call "C:\Program Files (x86)\NSIS\makensis.exe" janet-installer.nsi
- build_win dist
- copy janet-install.exe dist\install.exe
- call "C:\Program Files (x86)\NSIS\makensis.exe" janet-installer.nsi
build: off
@@ -33,9 +32,9 @@ only_commits:
- src/
artifacts:
- path: dist
name: janet-windows
type: Zip
- path: janet-installer.exe
name: janet-windows-installer.exe
type: File
deploy:
description: 'The Janet Programming Language.'

BIN
assets/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

11
assets/icon_svg.svg Normal file
View File

@@ -0,0 +1,11 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" viewBox="0 0 640 640" preserveAspectRatio="xMidYMid meet">
<g id="layer101" fill="#d45500" stroke="none">
<path d="M145 531 c-46 -31 -58 -75 -30 -118 21 -32 30 -22 44 47 7 30 19 62 27 71 26 29 1 29 -41 0z"/>
<path d="M341 534 c-23 -29 -26 -50 -11 -88 10 -28 64 -60 86 -52 12 5 12 2 0 -22 -24 -47 -51 -64 -116 -71 -51 -6 -65 -12 -85 -37 -14 -16 -24 -32 -25 -36 0 -12 -35 -9 -48 4 -7 7 -12 24 -12 38 0 41 -11 43 -47 8 -47 -46 -46 -90 5 -138 20 -19 49 -51 63 -70 l27 -35 88 0 c49 0 106 4 127 8 46 10 106 62 143 125 25 42 28 58 30 142 0 52 4 103 9 113 11 27 -14 75 -49 93 -41 21 -115 44 -143 44 -12 0 -31 -12 -42 -26z m89 -119 c0 -3 -2 -5 -5 -5 -3 0 -5 2 -5 5 0 3 2 5 5 5 3 0 5 -2 5 -5z"/>
</g>
<g id="layer102" fill="#deaa87" stroke="none">
<path d="M186 549 c-33 -31 -38 -43 -56 -137 -26 -135 -26 -163 3 -190 33 -31 49 -28 85 17 28 35 36 39 87 43 46 4 61 10 90 38 18 18 39 46 46 62 10 25 9 32 -5 46 -17 16 -19 16 -29 1 -8 -14 -15 -15 -34 -6 -27 12 -40 65 -24 96 10 17 8 23 -12 36 -13 8 -44 18 -69 21 -42 6 -49 4 -82 -27z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -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
@@ -131,6 +134,8 @@ copy src\include\janet.h dist\janet.h
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

View File

@@ -1,55 +1,157 @@
# Version
!define VERSION "0.6.0"
!define PRODUCT_VERSION "${VERSION}.0"
VIProductVersion "${PRODUCT_VERSION}"
VIFileVersion "${PRODUCT_VERSION}"
# Use the modern UI
!define MULTIUSER_EXECUTIONLEVEL Highest
!define MULTIUSER_MUI
!define MULTIUSER_INSTALLMODE_COMMANDLINE
!define MULTIUSER_INSTALLMODE_INSTDIR "janet"
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "Software\Janet\${VERSION}"
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME ""
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "Software\Janet\${VERSION}"
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME ""
!define MULTIUSER_INSTALLMODE_INSTDIR "Janet-${VERSION}"
!include "MultiUser.nsh"
!include "MUI2.nsh"
!include ".\tools\EnvVarUpdate.nsh"
# Basics
Name "Janet"
OutFile "janet-install.exe"
OutFile "janet-v${VERSION}-windows-installer.exe"
# Some Configuration
!define APPNAME "Janet"
!define DESCRIPTION "The Janet Programming Language"
!define HELPURL "http://janet-lang.org"
BrandingText "The Janet Programming Language"
# 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
!define MUI_ABORTWARNING
# Show a welcome page first
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "LICENSE"
!insertmacro MUI_PAGE_COMPONENTS
# Pick Install Directory
!insertmacro MULTIUSER_PAGE_INSTALLMODE
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
# Done
!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
!insertmacro MULTIUSER_INIT
functionEnd
Function .onInit
!insertmacro MULTIUSER_INIT
!insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd
section "Janet" BfWSection
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\bin\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_BINPATH "$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_BINPATH "$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
# Uninstaller
function un.onInit
!insertmacro MULTIUSER_UNINIT
functionEnd
section "uninstall"
# Remove Start Menu launcher
delete "$SMPROGRAMS\Janet.lnk"
# Remove files
delete "$INSTDIR\logo.ico"
rmdir /r "$INSTDIR\Library"
rmdir /r "$INSTDIR\bin"
rmdir /r "$INSTDIR\C"
# 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_BINPATH
DeleteRegValue HKCU "Environment" JANET_PATH
DeleteRegValue HKCU "Environment" JANET_HEADERPATH
DeleteRegValue HKCU "Environment" JANET_BINPATH
# 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"
# Remove uninstaller information from the registry
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Janet"
sectionEnd

1
janet_win.rc Normal file
View File

@@ -0,0 +1 @@
IDI_MYICON ICON "assets\icon.ico"

View File

@@ -130,6 +130,7 @@ janet_mainclient = executable('janet', core_src, core_image, init_gen, mainclien
include_directories : incdir,
dependencies : [m_dep, dl_dep],
install : true)
janet_jpm = install_data('tools/jpm', install_dir : 'bin')
# Documentation
docs = custom_target('docs',

View File

@@ -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)]
@@ -1686,15 +1687,16 @@
@{})
(defn dofile
"Evaluate a file in a new environment and return the new environment."
"Evaluate a file and return the resulting environment."
[path & args]
(def {:exit exit-on-error
:source source
:env env
:compile-only compile-only} (table ;args))
(def f (if (= (type path) :core/file)
path
(file/open path)))
(def newenv (make-env))
(default env (make-env))
(defn chunks [buf _] (file/read f 2048 buf))
(defn bp [&opt x y]
(def ret (bad-parse x y))
@@ -1704,7 +1706,7 @@
(def ret (bad-compile x y z))
(if exit-on-error (os/exit 1))
ret)
(run-context {:env newenv
(run-context {:env env
:chunks chunks
:on-parse-error bp
:on-compile-error bc
@@ -1715,7 +1717,7 @@
:compile-only compile-only
:source (or source (if (= f path) "<anonymous>" path))})
(when (not= f path) (file/close f))
(table/setproto newenv nil))
env)
(def module/loaders
"A table of loading method names to loading functions.

View File

@@ -26,16 +26,6 @@
#include "fiber.h"
#endif
static JanetBuildConfig *api_build_config = &(JanetBuildConfig){
.api_version = JANET_API_VERSION,
.single_threaded = JANET_SINGLE_THREADED_BIT,
.nanbox = JANET_NANBOX_BIT
};
const JanetBuildConfig *janet_build_config() {
return api_build_config;
}
void janet_panicv(Janet message) {
if (janet_vm_return_reg != NULL) {
*janet_vm_return_reg = message;

View File

@@ -57,13 +57,37 @@ typedef void *Clib;
JanetModule janet_native(const char *name, const uint8_t **error) {
Clib lib = load_clib(name);
JanetModule init;
JanetModconf getter;
if (!lib) {
*error = janet_cstring(error_clib());
return NULL;
}
init = (JanetModule) symbol_clib(lib, "_janet_init");
if (!init) {
*error = janet_cstring("could not find _janet_init symbol");
*error = janet_cstring("could not find the _janet_init symbol");
return NULL;
}
getter = (JanetModconf) symbol_clib(lib, "_janet_mod_config");
if (!getter) {
*error = janet_cstring("could not find the _janet_mod_config symbol");
return NULL;
}
JanetBuildConfig modconf = getter();
JanetBuildConfig host = janet_config_current();
if (host.major != modconf.major ||
host.minor < modconf.minor ||
host.bits != modconf.bits) {
char errbuf[128];
sprintf(errbuf, "config mismatch - host %d.%.d.%d(%.4x) vs. module %d.%d.%d(%.4x)",
host.major,
host.minor,
host.patch,
host.bits,
modconf.major,
modconf.minor,
modconf.patch,
modconf.bits);
*error = janet_cstring(errbuf);
return NULL;
}
return init;
@@ -830,6 +854,9 @@ JanetTable *janet_core_env(JanetTable *replacements) {
JDOC("The version number of the running janet program."));
janet_def(env, "janet/build", janet_cstringv(JANET_BUILD),
JDOC("The build identifier of the running janet program."));
janet_def(env, "janet/config-bits", janet_wrap_integer(JANET_CURRENT_CONFIG_BITS),
JDOC("The flag set of config options from janetconf.h which is used to check "
"if native modules are compatible with the host program."));
/* Allow references to the environment */
janet_def(env, "_env", janet_wrap_table(env), JDOC("The environment table for the current scope."));

View File

@@ -32,6 +32,10 @@
#include "util.h"
#endif
#ifndef JANET_WINDOWS
#include <sys/wait.h>
#endif
#define IO_WRITE 1
#define IO_READ 2
#define IO_APPEND 4
@@ -285,13 +289,17 @@ static Janet cfun_io_fclose(int32_t argc, Janet *argv) {
if (iof->flags & IO_PIPED) {
#ifdef JANET_WINDOWS
#define pclose _pclose
#define WEXITSTATUS(x) x
#endif
if (pclose(iof->file)) janet_panic("could not close file");
int status = pclose(iof->file);
iof->flags |= IO_CLOSED;
if (status == -1) janet_panic("could not close file");
return janet_wrap_integer(WEXITSTATUS(status));
} else {
if (fclose(iof->file)) janet_panic("could not close file");
iof->flags |= IO_CLOSED;
return janet_wrap_nil();
}
iof->flags |= IO_CLOSED;
return argv[0];
}
/* Seek a file */

View File

@@ -41,7 +41,9 @@
#include <direct.h>
#include <sys/utime.h>
#include <io.h>
#include <process.h>
#else
#include <spawn.h>
#include <utime.h>
#include <unistd.h>
#include <dirent.h>
@@ -88,7 +90,7 @@ static Janet os_exit(int32_t argc, Janet *argv) {
}
#ifdef JANET_REDUCED_OS
/* Provide a dud os/getenv so init.janet works, but nothing else */
/* Provide a dud os/getenv so boot.janet and init.janet work, but nothing else */
static Janet os_getenv(int32_t argc, Janet *argv) {
(void) argv;
@@ -99,97 +101,152 @@ static Janet os_getenv(int32_t argc, Janet *argv) {
#else
/* Provide full os functionality */
#ifdef JANET_WINDOWS
static Janet os_execute(int32_t argc, Janet *argv) {
janet_arity(argc, 1, -1);
JanetBuffer *buffer = janet_buffer(10);
for (int32_t i = 0; i < argc; i++) {
const uint8_t *argstring = janet_getstring(argv, i);
janet_buffer_push_bytes(buffer, argstring, janet_string_length(argstring));
if (i != argc - 1) {
janet_buffer_push_u8(buffer, ' ');
#define JANET_OS_EFLAG_E 0x1
#define JANET_OS_EFLAG_P 0x2
/* Get flags */
/* Unfortunately, execvpe is linux (glibc) only. Instead, we can switch
* between the more portable execve, execvp, or execv.
* Use the :e or :p flag for execve and execvp respectively. Eventually
* :ep or :pe could be execvpe. */
static int os_execute_flags(int32_t argc, const Janet *argv) {
if (argc < 2) return 0;
int flags = 0;
if (argc > 1) {
const uint8_t *f = janet_getkeyword(argv, 1);
int32_t len = janet_string_length(f);
for (int32_t i = 0; i < len; i++) {
if (f[i] == 'e') flags |= JANET_OS_EFLAG_E;
if (f[i] == 'p') flags |= JANET_OS_EFLAG_P;
}
}
janet_buffer_push_u8(buffer, 0);
/* Convert to wide chars */
wchar_t *sys_str = malloc(buffer->count * sizeof(wchar_t));
if (NULL == sys_str) {
JANET_OUT_OF_MEMORY;
}
int nwritten = MultiByteToWideChar(
CP_UTF8,
MB_PRECOMPOSED,
buffer->data,
buffer->count,
sys_str,
buffer->count);
if (nwritten == 0) {
free(sys_str);
janet_panic("could not create process");
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess(NULL,
(LPSTR) sys_str,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi)) {
free(sys_str);
janet_panic("could not create process");
}
free(sys_str);
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
WORD status;
GetExitCodeProcess(pi.hProcess, (LPDWORD)&status);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return janet_wrap_integer(status);
return flags;
}
#else
/* Get env for os_execute (execv family of functions, as well as CreateProcess) */
static char **os_execute_env(int32_t argc, const Janet *argv) {
char **envp = NULL;
if (argc > 2) {
JanetDictView dict = janet_getdictionary(argv, 2);
envp = malloc(sizeof(char *) * (dict.len + 1));
if (NULL == envp) {
JANET_OUT_OF_MEMORY;
}
int32_t j = 0;
for (int32_t i = 0; i < dict.cap; i++) {
const JanetKV *kv = dict.kvs + i;
if (!janet_checktype(kv->key, JANET_STRING)) continue;
if (!janet_checktype(kv->value, JANET_STRING)) continue;
const uint8_t *keys = janet_unwrap_string(kv->key);
const uint8_t *vals = janet_unwrap_string(kv->value);
int32_t klen = janet_string_length(keys);
int32_t vlen = janet_string_length(vals);
/* Check keys has no embedded 0s or =s. */
int skip = 0;
for (int32_t k = 0; k < klen; k++) {
if (keys[k] == '\0' || keys[k] == '=') {
skip = 1;
break;
}
}
if (skip) continue;
char *envitem = malloc(klen + vlen + 2);
if (NULL == envitem) {
JANET_OUT_OF_MEMORY;
}
memcpy(envitem, keys, klen);
envitem[klen] = '=';
memcpy(envitem + klen + 1, vals, vlen);
envitem[klen + vlen + 1] = 0;
envp[j++] = envitem;
}
envp[j] = NULL;
}
return envp;
}
/* Free memory from os_execute */
static void os_execute_cleanup(char **envp, const char **child_argv) {
free((void *)child_argv);
if (NULL != envp) {
char **envitem = envp;
while (*envitem != NULL) {
free(*envitem);
envitem++;
}
}
free(envp);
}
static Janet os_execute(int32_t argc, Janet *argv) {
janet_arity(argc, 1, -1);
const char **child_argv = malloc(sizeof(char *) * (argc + 1));
janet_arity(argc, 1, 3);
/* Get arguments */
JanetView exargs = janet_getindexed(argv, 0);
const char **child_argv = malloc(sizeof(char *) * (exargs.len + 1));
int status = 0;
if (NULL == child_argv) {
JANET_OUT_OF_MEMORY;
}
for (int32_t i = 0; i < argc; i++) {
child_argv[i] = janet_getcstring(argv, i);
for (int32_t i = 0; i < exargs.len; i++) {
child_argv[i] = janet_getcstring(exargs.items, i);
}
child_argv[argc] = NULL;
child_argv[exargs.len] = NULL;
/* Fork child process */
pid_t pid = fork();
if (pid < 0) {
janet_panic("failed to execute");
} else if (pid == 0) {
if (-1 == execve(child_argv[0], (char **)child_argv, NULL)) {
exit(1);
}
/* Get flags */
int flags = os_execute_flags(argc, argv);
/* Get environment */
char **envp = os_execute_env(argc, argv);
/* Coerce to form that works for spawn. I'm fairly confident no implementation
* of posix_spawn would modify the argv array passed in. */
char *const *cargv = (char *const *)child_argv;
#ifdef JANET_WINDOWS
/* Use _spawn family of functions. */
/* Windows docs say do this before any spawns. */
_flushall();
if (flags & (JANET_OS_EFLAG_P | JANET_OS_EFLAG_E)) {
status = (int) _spawnvpe(_P_WAIT, child_argv[0], cargv, envp);
} else if (flags & JANET_OS_EFLAG_P) {
status = (int) _spawnvp(_P_WAIT, child_argv[0], cargv);
} else if (flags & JANET_OS_EFLAG_E) {
status = (int) _spawnve(_P_WAIT, child_argv[0], cargv, envp);
} else {
status = (int) _spawnv(_P_WAIT, child_argv[0], cargv);
}
os_execute_cleanup(envp, child_argv);
return janet_wrap_integer(status);
#else
/* Use posix_spawn to spawn new process */
pid_t pid;
if (flags & JANET_OS_EFLAG_P) {
status = posix_spawnp(&pid,
child_argv[0], NULL, NULL, cargv,
(flags & JANET_OS_EFLAG_E) ? envp : NULL);
} else {
status = posix_spawn(&pid,
child_argv[0], NULL, NULL, cargv,
(flags & JANET_OS_EFLAG_E) ? envp : NULL);
}
/* Wait for child */
if (status) {
os_execute_cleanup(envp, child_argv);
janet_panic(strerror(status));
} else {
waitpid(pid, &status, 0);
}
free(child_argv);
return janet_wrap_integer(status);
}
os_execute_cleanup(envp, child_argv);
return janet_wrap_integer(WEXITSTATUS(status));
#endif
}
static Janet os_shell(int32_t argc, Janet *argv) {
janet_arity(argc, 0, 1);
@@ -607,6 +664,17 @@ static Janet os_dir(int32_t argc, Janet *argv) {
return janet_wrap_array(paths);
}
static Janet os_rename(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
const char *src = janet_getcstring(argv, 0);
const char *dest = janet_getcstring(argv, 1);
int status = rename(src, dest);
if (status) {
janet_panic(strerror(errno));
}
return janet_wrap_nil();
}
#endif /* JANET_REDUCED_OS */
static const JanetReg os_cfuns[] = {
@@ -690,9 +758,15 @@ static const JanetReg os_cfuns[] = {
},
{
"os/execute", os_execute,
JDOC("(os/execute program & args)\n\n"
"Execute a program on the system and pass it string arguments. Returns "
"the exit status of the program.")
JDOC("(os/execute args &opts flags env)\n\n"
"Execute a program on the system and pass it string arguments. Flags "
"is a keyword that modifies how the program will execute.\n\n"
"\t:e - enables passing an environment to the program. Without :e, the "
"current environment is inherited.\n"
"\t:p - allows searching the current PATH for the binary to execute. "
"Without this flag, binaries must use absolute paths.\n\n"
"env is a table or struct mapping environment variables to values. "
"Returns the exit status of the program.")
},
{
"os/shell", os_shell,
@@ -742,6 +816,11 @@ static const JanetReg os_cfuns[] = {
"\t:year-day - day of the year [0-365]\n"
"\t:dst - If Day Light Savings is in effect")
},
{
"os/rename", os_rename,
JDOC("(os/rename oldname newname)\n\n"
"Rename a file on disk to a new path. Returns nil.")
},
#endif
{NULL, NULL, NULL}
};

View File

@@ -23,6 +23,9 @@
#ifndef JANET_UTIL_H_defined
#define JANET_UTIL_H_defined
#include <stdio.h>
#include <errno.h>
#ifndef JANET_AMALG
#include <janet.h>
#endif

View File

@@ -31,8 +31,6 @@ extern "C" {
#include "janetconf.h"
#define JANET_API_VERSION 1
#ifndef JANET_VERSION
#define JANET_VERSION "latest"
#endif
@@ -186,26 +184,38 @@ extern "C" {
#endif
#endif
/* Runtime config constants */
#ifdef JANET_NO_NANBOX
#define JANET_NANBOX_BIT 0
#else
#define JANET_NANBOX_BIT 1
#define JANET_NANBOX_BIT 0x1
#endif
#ifdef JANET_SINGLE_THREADED
#define JANET_SINGLE_THREADED_BIT 1
#define JANET_SINGLE_THREADED_BIT 0x2
#else
#define JANET_SINGLE_THREADED_BIT 0
#endif
#define JANET_CURRENT_CONFIG_BITS \
(JANET_SINGLE_THREADED_BIT | \
JANET_NANBOX_BIT)
/* Represents the settings used to compile Janet, as well as the version */
typedef struct {
int api_version;
int single_threaded : 1;
int nanbox : 1;
unsigned major;
unsigned minor;
unsigned patch;
unsigned bits;
} JanetBuildConfig;
/* Get config of current compilation unit. */
#define janet_config_current() ((JanetBuildConfig){ \
JANET_VERSION_MAJOR, \
JANET_VERSION_MINOR, \
JANET_VERSION_PATCH, \
JANET_CURRENT_CONFIG_BITS })
/***** END SECTION CONFIG *****/
/***** START SECTION TYPES *****/
@@ -1206,6 +1216,7 @@ JANET_API void *janet_abstract(const JanetAbstractType *type, size_t size);
/* Native */
typedef void (*JanetModule)(JanetTable *);
typedef JanetBuildConfig(*JanetModconf)(void);
JANET_API JanetModule janet_native(const char *name, const uint8_t **error);
/* Marshaling */
@@ -1276,15 +1287,11 @@ JANET_API void janet_register(const char *name, JanetCFunction cfun);
/* New C API */
#define JANET_MODULE_ENTRY JANET_API void _janet_init
JANET_API int janet_api_version();
JANET_API const JanetBuildConfig *janet_build_config();
#define janet_api_compatible() \
((janet_api_build_config()->api_version == JANET_API_VERSION) \
&& (janet_api_build_config()->nanbox == JANET_NANBOX_BIT) \
&& (janet_api_build_config()->single_threaded == JANET_SINGLE_THREADED_BIT))
#define JANET_MODULE_ENTRY \
JANET_API JanetBuildConfig _janet_mod_config(void) { \
return janet_config_current(); \
} \
JANET_API void _janet_init
JANET_API void janet_panicv(Janet message);
JANET_API void janet_panic(const char *message);

View File

@@ -25,22 +25,29 @@
#ifndef JANETCONF_H
#define JANETCONF_H
#define JANET_VERSION "1.0.0"
#define JANET_VERSION_MAJOR 0
#define JANET_VERSION_MINOR 6
#define JANET_VERSION_PATCH 0
#define JANET_VERSION_EXTRA "-dev"
#define JANET_VERSION "0.6.0-dev"
/* #define JANET_BUILD "local" */
/* These settings all affect linking, so use cautiously. */
/* #define JANET_SINGLE_THREADED */
/* #define JANET_NO_DYNAMIC_MODULES */
/* #define JANET_NO_NANBOX */
/* #define JANET_API __attribute__((visibility ("default"))) */
/* #define JANET_NO_ASSEMBLER */
/* #define JANET_NO_PEG */
/* #define JANET_NO_TYPED_ARRAY */
/* #define JANET_NO_INT_TYPES */
/* #define JANET_REDUCED_OS */
/* #define JANET_API __attribute__((visibility ("default"))) */
/* #define JANET_OUT_OF_MEMORY do { printf("janet out of memory\n"); exit(1); } while (0) */
/* #define JANET_RECURSION_GUARD 1024 */
/* #define JANET_MAX_PROTO_DEPTH 200 */
/* #define JANET_MAX_MACRO_EXPAND 200 */
/* #define JANET_STACK_MAX 16384 */
/* #define JANET_NO_NANBOX */
#endif /* end of include guard: JANETCONF_H */

View File

@@ -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

View File

@@ -1,11 +0,0 @@
(import cook)
(cook/make-native
:name "testmod"
:source @["testmod.c"])
(import build/testmod :as testmod)
(if (not= 5 (testmod/get5)) (error "testmod/get5 failed"))
(print "OK!")

View File

@@ -0,0 +1,7 @@
(declare-project
:name "testmod")
(declare-native
:name "testmod"
:source @["testmod.c"])

View File

@@ -0,0 +1,3 @@
(import build/testmod :as testmod)
(if (not= 5 (testmod/get5)) (error "testmod/get5 failed"))

327
tools/EnvVarUpdate.nsh Normal file
View File

@@ -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 '<space>;'
${Loop}
${Do}
${${UN}StrStr} $7 $0 "; "
${If} $7 == ""
${ExitDo}
${EndIf}
${${UN}StrRep} $0 $0 "; " ";" ; Remove ';<space>'
${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 ';<EnvVar>' to '<EnvVar>'
${EndIf}
StrLen $6 $0
IntOp $6 $6 - 1
StrCpy $7 $0 1 $6
${If} $7 == ";"
StrCpy $0 $0 $6 ; Change ';<EnvVar>' to '<EnvVar>'
${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

View File

@@ -1,5 +1,13 @@
# Library to help build janet natives and other
# build artifacts.
### cook.janet
###
### Library to help build janet natives and other
### build artifacts.
###
### Copyright 2019 © Calvin Rose
#
# Basic Path Settings
#
# Windows is the OS outlier
(def- is-win (= (os/which) :windows))
@@ -8,18 +16,142 @@
(def- objext (if is-win ".obj" ".o"))
(def- modext (if is-win ".dll" ".so"))
(def prefix (or (os/getenv "PREFIX") "/usr/local"))
#
# Rule Engine
#
(defn- getrules []
(def rules (dyn :rules))
(if rules rules (setdyn :rules @{})))
(defn- gettarget [target]
(def item ((getrules) target))
(unless item (error (string "No rule for target " target)))
item)
(defn- rule-impl
[target deps thunk &opt phony]
(put (getrules) target @[(array/slice deps) thunk phony]))
(defmacro rule
"Add a rule to the rule graph."
[target deps & body]
~(,rule-impl ,target ,deps (fn [] nil ,;body)))
(defmacro phony
"Add a phony rule to the rule graph. A phony rule will run every time
(it is always considered out of date). Phony rules are good for defining
user facing tasks."
[target deps & body]
~(,rule-impl ,target ,deps (fn [] nil ,;body) true))
(defn add-dep
"Add a dependency to an existing rule. Useful for extending phony
rules or extending the dependency graph of existing rules."
[target dep]
(def [deps] (gettarget target))
(array/push deps dep))
(defn- add-thunk
[target more]
(def item (gettarget target))
(def [_ thunk] item)
(put item 1 (fn [] (more) (thunk))))
(defmacro add-body
"Add recipe code to an existing rule. This makes existing rules do more but
does not modify the dependency graph."
[target & body]
~(,add-thunk ,target (fn [] ,;body)))
(defn- needs-build
[dest src]
(let [mod-dest (os/stat dest :modified)
mod-src (os/stat src :modified)]
(< mod-dest mod-src)))
(defn- needs-build-some
[dest sources]
(def f (file/open dest))
(if (not f) (break true))
(file/close f)
(some (partial needs-build dest) sources))
(defn do-rule
"Evaluate a given rule."
[target]
(def item ((getrules) target))
(unless item
(if (os/stat target :mode)
(break target)
(error (string "No rule for file " target " found."))))
(def [deps thunk phony] item)
(def realdeps (seq [dep :in deps :let [x (do-rule dep)] :when x] x))
(when (or phony (needs-build-some target realdeps))
(thunk))
(unless phony target))
(def- _env (fiber/getenv (fiber/current)))
(defn- import-rules*
[path & args]
(def [realpath] (module/find path))
(def env (make-env))
(loop [k :keys _env :when (symbol? k)]
(unless ((_env k) :private) (put env k (_env k))))
(def currenv (fiber/getenv (fiber/current)))
(loop [k :keys currenv :when (keyword? k)]
(put env k (currenv k)))
(require path :env env ;args)
(when-let [rules (env :rules)] (merge-into (getrules) rules)))
(defmacro import-rules
"Import another file that defines more cook rules. This ruleset
is merged into the current ruleset."
[path & args]
~(,import-rules* ,(string path) ,;args))
#
# Configuration
#
# Installation settings
(def JANET_MODPATH (or (os/getenv "JANET_MODPATH") module/*syspath*))
(def JANET_HEADERPATH (or (os/getenv "JANET_HEADERPATH") module/*headerpath*))
(def JANET_BINPATH (or (os/getenv "JANET_BINPATH") (unless is-win "/usr/local/bin")))
# 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 " /nologo"
(string " -shared"
(if is-mac " -undefined dynamic_lookup" "")))))
(def CFLAGS (or (os/getenv "CFLAGS") (if is-win "" " -std=c99 -Wall -Wextra -fpic")))
(defn- opt
"Get an option, allowing overrides via dynamic bindings AND some
default value dflt if no dynamic binding is set."
[opts key dflt]
(def ret (or (opts key) (dyn key dflt)))
(if (= nil ret)
(error (string "option :" key " not set")))
ret)
#
# OS and shell helpers
#
(defn shell
"Do a shell command"
[& args]
(def cmd (string ;args))
(def cmd (string/join args))
(print cmd)
(def res (os/shell cmd))
(unless (zero? res)
(error (string "command exited with status " res))))
(defn- rm
(defn rm
"Remove a directory and all sub directories."
[path]
(if (= (os/stat path :mode) :directory)
@@ -29,19 +161,14 @@
(os/rmdir path))
(os/rm path)))
(defn- needs-build
[dest src]
"Check if dest is older than src. Used for checking if a file should be updated."
(def f (file/open dest))
(if (not f) (break true))
(file/close f)
(let [mod-dest (os/stat dest :modified)
mod-src (os/stat src :modified)]
(< mod-dest mod-src)))
(defn copy
"Copy a file or directory recursively from one location to another."
[src dest]
(shell (if is-win "xcopy " "cp -rf ") `"` src `" "` dest (if is-win `" /y /e` `"`)))
(defn- needs-build-some
[f others]
(some (partial needs-build f) others))
#
# C Compilation
#
(defn- embed-name
"Rename a janet symbol for embedding."
@@ -82,10 +209,10 @@
(defn- make-define
"Generate strings for adding custom defines to the compiler."
[define value]
(def prefix (if is-win "/D" "-D"))
(def pre (if is-win "/D" "-D"))
(if value
(string prefix define "=" value)
(string prefix define)))
(string pre define "=" value)
(string pre define)))
(defn- make-defines
"Generate many defines. Takes a dictionary of defines. If a value is
@@ -93,102 +220,149 @@
[defines]
(seq [[d v] :pairs defines] (make-define d (if (not= v true) v))))
# Defaults
(def OPTIMIZE 2)
(def CC (if is-win "cl" "cc"))
(def LD (if is-win
"link"
(string CC
" -shared"
(if is-mac " -undefined dynamic_lookup" ""))))
(def CFLAGS (string
(if is-win "/I" "-I")
module/*headerpath*
(if is-win " /O" " -std=c99 -Wall -Wextra -fpic -O")
OPTIMIZE))
(defn- getcflags
"Generate the c flags from the input options."
[opts]
(string (opt opts :cflags CFLAGS)
(if is-win " /I\"" " \"-I")
(opt opts :headerpath JANET_HEADERPATH)
`"`
(if is-win " /O\"" " \"-O")
(opt opts :optimize OPTIMIZE)
`"`))
(defn- compile-c
"Compile a C file into an object file."
[opts src dest]
(def cc (or (opts :compiler) CC))
(def cflags (or (opts :cflags) CFLAGS))
(def defines (interpose " " (make-defines (or (opts :defines) {}))))
(if (needs-build dest src)
(if is-win
(shell cc " " ;defines " /nologo /c " cflags " /Fo" dest " " src)
(shell cc " -c " src " " ;defines " " cflags " -o " dest))))
(def cc (opt opts :compiler CC))
(def cflags (getcflags opts))
(def defines (interpose " " (make-defines (opt opts :defines {}))))
(rule dest [src]
(if is-win
(shell cc " " ;defines " /nologo /c " cflags " /Fo\"" dest `" "` src `"`)
(shell cc " -c '" src "' " ;defines " " cflags " -o '" dest `'`))))
(defn- link-c
"Link a number of object files together."
[opts target & objects]
(def ld (or (opts :linker) LD))
(def cflags (or (opts :cflags) CFLAGS))
(def lflags (or (opts :lflags) ""))
(def olist (string/join objects " "))
(if (needs-build-some target objects)
(if is-win
(shell ld " /DLL /OUT:" target " " olist " %JANET_PATH%\\janet.lib")
(shell ld " " cflags " -o " target " " olist " " lflags))))
(def ld (opt opts :linker LD))
(def cflags (getcflags opts))
(def lflags (opt opts :lflags LDFLAGS))
(def olist (string/join objects `" "`))
(rule target objects
(if is-win
(shell ld " " lflags " /DLL /OUT:" target ` "` olist `" "` (opt opts :headerpath JANET_HEADERPATH) `"\\janet.lib`)
(shell ld " " cflags ` -o "` target `" "` olist `" ` lflags))))
(defn- create-buffer-c
"Inline raw byte file as a c file."
[source dest name]
(when (needs-build dest source)
(def f (file/open source :r))
(if (not f) (error (string "file " f " not found")))
(def out (file/open dest :w))
(def chunks (seq [b :in (file/read f :all)] (string b)))
(file/write out
"#include <janet.h>\n"
"static const unsigned char bytes[] = {"
;(interpose ", " chunks)
"};\n\n"
"const unsigned char *" name "_embed = bytes;\n"
"size_t " name "_embed_size = sizeof(bytes);\n")
(file/close out)
(file/close f)))
(rule dest [source]
(def f (file/open source :r))
(if (not f) (error (string "file " f " not found")))
(def out (file/open dest :w))
(def chunks (seq [b :in (file/read f :all)] (string b)))
(file/write out
"#include <janet.h>\n"
"static const unsigned char bytes[] = {"
;(interpose ", " chunks)
"};\n\n"
"const unsigned char *" name "_embed = bytes;\n"
"size_t " name "_embed_size = sizeof(bytes);\n")
(file/close out)
(file/close f)))
# Public
#
# Declaring Artifacts - used in project.janet, targets specifically
# tailored for janet.
#
(defn make-native
"Build a native binary. This is a shared library that can be loaded
(defn- install-rule
"Add install and uninstall rule for moving file from src into destdir."
[src destdir]
(def parts (string/split sep src))
(def name (last parts))
(add-body "install"
(try (os/mkdir destdir) ([err] nil))
(copy src destdir))
(add-body "uninstall"
(def path (string destdir sep name))
(print "removing " path)
(try (rm path) ([err]
(unless (= err "No such file or directory")
(error err))))))
(defn declare-native
"Declare a native binary. This is a shared library that can be loaded
dynamically by a janet runtime."
[& opts]
(def opt-table (table ;opts))
(os/mkdir "build")
(def sources (opt-table :source))
(def name (opt-table :name))
[&keys opts]
(def sources (opts :source))
(def name (opts :name))
(def lname (lib-name name))
(loop [src :in sources]
(compile-c opt-table src (object-name src)))
(compile-c opts src (object-name src)))
(def objects (map object-name sources))
(when-let [embedded (opt-table :embedded)]
(loop [src :in embedded]
(def c-src (embed-c-name src))
(def o-src (embed-o-name src))
(array/push objects o-src)
(create-buffer-c src c-src (embed-name src))
(compile-c opt-table c-src o-src)))
(link-c opt-table (lib-name name) ;objects))
(when-let [embedded (opts :embedded)]
(loop [src :in embedded]
(def c-src (embed-c-name src))
(def o-src (embed-o-name src))
(array/push objects o-src)
(create-buffer-c src c-src (embed-name src))
(compile-c opts c-src o-src)))
(link-c opts lname ;objects)
(add-dep "build" lname)
(def path (opt opts :modpath JANET_MODPATH))
(install-rule lname path))
(defn clean
"Remove all built artifacts."
[]
(rm "build"))
(defn declare-source
"Create a Janet modules. This does not actually build the module(s),
but registers it for packaging and installation."
[&keys opts]
(def sources (opts :source))
(def path (opt opts :modpath JANET_MODPATH))
(each s sources
(install-rule s path)))
(defn make-archive
(defn declare-binscript
"Declare a janet file to be installed as an executable script."
[&keys opts]
(def main (opts :main))
(def binpath (opt opts :binpath JANET_BINPATH))
(install-rule main binpath))
(defn declare-archive
"Build a janet archive. This is a file that bundles together many janet
scripts into a janet image. This file can the be moved to any machine with
a janet vm and the required dependencies and run there."
[& opts]
(def opt-table (table ;opts))
(os/mkdir "build")
(def entry (opt-table :entry))
(def name (opt-table :name))
(spit (string name ".jimage") (make-image (require entry))))
[&keys opts]
(def entry (opts :entry))
(def name (opts :name))
(def iname (string "build" sep name ".jimage"))
(rule iname (or (opts :deps) [])
(spit iname (make-image (require entry))))
(def path (opt opts :modpath JANET_MODPATH))
(install-rule iname path))
(defn make-binary
"Make a binary executable that can be run on the current platform. This function
generates a self contained binary that can be run of the same architecture as the
build machine, as the current janet vm will be packaged with the output binary."
[& opts]
(error "Not Yet Implemented."))
(defn declare-project
"Define your project metadata. This should
be the first declaration in a project.janet file.
Also sets up basic phony targets like clean, build, test, etc."
[&keys meta]
(setdyn :project meta)
(try (os/mkdir "build") ([err] nil))
(phony "build" [])
(phony "install" ["build"] (print "Installed."))
(phony "uninstall" [] (print "Uninstalled."))
(phony "clean" [] (rm "build") (print "Deleted build directory."))
(phony "test" ["build"]
(defn dodir
[dir]
(each sub (os/dir dir)
(def ndir (string dir sep sub))
(case (os/stat ndir :mode)
:file (when (string/has-suffix? ".janet" ndir)
(print "running " ndir " ...")
(dofile ndir :exit true))
:directory (dodir ndir))))
(dodir "test")
(print "All tests passed.")))

41
tools/jpm Executable file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env janet
# CLI tool for building janet projects. Wraps cook.
(import cook)
(def- argpeg
(peg/compile
'(* "--" '(some (if-not "=" 1)) "=" '(any 1))))
(defn- help
[]
(print "usage: jpm [targets]... --key=value ...")
(print "Available targets are:")
(each k (sort (keys (dyn :rules @{})))
(print " " k))
(print `
Keys are:
--modpath : The directory to install modules to. Defaults to $JANET_MODPATH or module/*syspath*
--headerpath : The directory containing janet headers. Defaults to $JANET_HEADERPATH or module/*headerpath*
--binpath : The directory to install binaries and scripts. Defaults to $JANET_BINPATH.
--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.
--cflags : Extra compiler flags for native modules. Defaults to $CFLAGS if set.
--lflags : Extra linker flags for native modules. Defaults to $LFLAGS if set.
`))
(def args (tuple/slice process/args 2))
(def todo @[])
(each arg args
(if (string/has-prefix? "--" arg)
(let [[key value] (peg/match argpeg arg)]
(setdyn (keyword key) value))
(array/push todo arg)))
(cook/import-rules "./project.janet")
(if (empty? todo) (help))
(each rule todo (cook/do-rule rule))

4
tools/jpm.bat Normal file
View File

@@ -0,0 +1,4 @@
@echo off
@rem Wrapper arounf jpm
janet %~dp0\jpm.janet %*