Experimental Windows support

This commit is contained in:
K Lange 2021-01-19 12:38:52 +09:00
parent f4444cccaa
commit a9b04cceb2
6 changed files with 145 additions and 53 deletions

2
.gitignore vendored
View File

@ -1,5 +1,7 @@
*.o *.o
*.so *.so
kuroko kuroko
*.exe
*.dll
wasm/ wasm/
jupyter/ jupyter/

View File

@ -5,9 +5,13 @@ OBJS = $(patsubst %.c, %.o, $(filter-out rline.c,$(filter-out kuroko.c,$(sor
MODULES = $(patsubst src/%.c, modules/%.so, $(sort $(wildcard src/*.c))) MODULES = $(patsubst src/%.c, modules/%.so, $(sort $(wildcard src/*.c)))
ifndef KRK_ENABLE_STATIC ifndef KRK_ENABLE_STATIC
CFLAGS += -fPIC CFLAGS += -fPIC -L.
LDFLAGS += -L. -Wl,-rpath -Wl,'$$ORIGIN' -Wl,-z,origin ifeq (,$(findstring mingw,$(CC)))
LDLIBS += -lkuroko -ldl LDFLAGS += -Wl,-rpath -Wl,'$$ORIGIN' -Wl,-z,origin
LDLIBS += -ldl -lkuroko
else
LDLIBS += libkuroko.so
endif
all: ${TARGET} ${MODULES} all: ${TARGET} ${MODULES}
KUROKO_LIBS = libkuroko.so KUROKO_LIBS = libkuroko.so
else else
@ -48,13 +52,13 @@ kuroko: ${KUROKO_LIBS}
%.o: *.h %.o: *.h
modules/%.so: src/%.c modules/%.so: src/%.c
${CC} ${CFLAGS} -shared -o $@ $< ${CC} ${CFLAGS} -shared -o $@ $< ${LDLIBS}
modules/math.so: src/math.c modules/math.so: src/math.c
${CC} ${CFLAGS} -shared -o $@ $< -lm ${CC} ${CFLAGS} -shared -o $@ $< -lm ${LDLIBS}
libkuroko.so: ${OBJS} libkuroko.so: ${OBJS}
${CC} ${CLFAGS} -shared -o $@ ${OBJS} ${CC} ${CFLAGS} -shared -o $@ ${OBJS}
builtins.c: builtins.krk builtins.c: builtins.krk
echo "const char krk_builtinsSrc[] = " > builtins.c echo "const char krk_builtinsSrc[] = " > builtins.c
@ -63,7 +67,7 @@ builtins.c: builtins.krk
.PHONY: clean .PHONY: clean
clean: clean:
@rm -f ${OBJS} ${TARGET} ${MODULES} libkuroko.so rline.o kuroko.o src/*.o @rm -f ${OBJS} ${TARGET} ${MODULES} libkuroko.so rline.o kuroko.o src/*.o kuroko.exe
tags: $(wildcard *.c) $(wildcard *.h) tags: $(wildcard *.c) $(wildcard *.h)
@ctags --c-kinds=+lx *.c *.h @ctags --c-kinds=+lx *.c *.h

View File

@ -60,6 +60,14 @@ Additional options include `KRK_DISABLE_RLINE=1` to not link with the included r
See [klange/kuroko-wasm-repl](https://github.com/klange/kuroko-wasm-repl) for information on building Kuroko with Emscripten for use in a web browser. See [klange/kuroko-wasm-repl](https://github.com/klange/kuroko-wasm-repl) for information on building Kuroko with Emscripten for use in a web browser.
### Building for Windows
Experimental support is available for building Kuroko to run on Windows using MingW:
CC=x86_64-w64-mingw32-gcc make
A capable terminal, such as Windows Terminal, is required to run the interpreter's REPL correctly. The older "Command Prompt" (cmd.exe) is specifically known to _not_ work.
## Code Examples ## Code Examples
_**NOTE**: Due to limitations with Github's markdown renderer, these snippets will be highlighted as Python code._ _**NOTE**: Due to limitations with Github's markdown renderer, these snippets will be highlighted as Python code._

84
rline.c
View File

@ -13,14 +13,19 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <ctype.h> #include <ctype.h>
#include <termios.h>
#include <string.h> #include <string.h>
#include <wchar.h> #include <wchar.h>
#include <unistd.h> #include <unistd.h>
#include <locale.h> #include <locale.h>
#include <poll.h>
#include <signal.h> #include <signal.h>
#ifndef _WIN32
#include <termios.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#else
#include <windows.h>
/* How do we get this in Windows? Seems WT asks the font? */
#define wcwidth(c) (1)
#endif
#ifdef __toaru__ #ifdef __toaru__
#include <toaru/rline.h> #include <toaru/rline.h>
#else #else
@ -223,35 +228,15 @@ int rline_exp_set_tab_complete_func(rline_callback_t func) {
return 0; return 0;
} }
#if 0
static int _unget = -1;
static void _ungetc(int c) {
_unget = c;
}
#endif
static int getch(int immediate, int timeout) { static int getch(int immediate, int timeout) {
#ifndef _WIN32
return fgetc(stdin); return fgetc(stdin);
#if 0 #else
if (_unget != -1) { TCHAR buf[1];
int out = _unget; DWORD dwRead;
_unget = -1; while (!ReadConsole(GetStdHandle(STD_INPUT_HANDLE),buf,1,&dwRead,NULL));
return out; return buf[0];
} #endif
if (immediate) return fgetc(stdin);
struct pollfd fds[1];
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
int ret = poll(fds,1,50);
if (ret > 0 && fds[0].revents & POLLIN) {
unsigned char buf[1];
int unused = read(STDIN_FILENO, buf, 1);
(void)unused;
return buf[0];
} else {
return -1;
}
#endif
} }
/** /**
@ -298,7 +283,7 @@ static int to_eight(uint32_t codepoint, char * out) {
* This is copied from bim. Supports a few useful * This is copied from bim. Supports a few useful
* things like rendering escapes as codepoints. * things like rendering escapes as codepoints.
*/ */
static int codepoint_width(wchar_t codepoint) { static int codepoint_width(int codepoint) {
if (codepoint == '\t') { if (codepoint == '\t') {
return 1; /* Recalculate later */ return 1; /* Recalculate later */
} }
@ -1365,15 +1350,18 @@ static void render_line(void) {
set_colors(COLOR_FG, COLOR_BG); set_colors(COLOR_FG, COLOR_BG);
/* Fill to end right hand side */
for (; j < width + offset - prompt_width_calc; ++j) {
printf(" ");
}
/* Print right hand side */
if (show_right_side) { if (show_right_side) {
/* Fill to end right hand side */
for (; j < width + offset - prompt_width_calc; ++j) {
printf(" ");
}
/* Print right hand side */
printf("\033[0m%s", prompt_right); printf("\033[0m%s", prompt_right);
} else {
printf("\033[0K");
} }
fflush(stdout);
} }
/** /**
@ -1424,9 +1412,15 @@ static line_t * line_insert(line_t * line, char_t c, int offset) {
* We don't listen for sigwinch for various reasons... * We don't listen for sigwinch for various reasons...
*/ */
static void get_size(void) { static void get_size(void) {
#ifndef _WIN32
struct winsize w; struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
rline_terminal_width = w.ws_col; rline_terminal_width = w.ws_col;
#else
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
rline_terminal_width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
#endif
if (rline_terminal_width - prompt_right_width - prompt_width > MINIMUM_SIZE) { if (rline_terminal_width - prompt_right_width - prompt_width > MINIMUM_SIZE) {
show_right_side = 1; show_right_side = 1;
show_left_side = 1; show_left_side = 1;
@ -1778,6 +1772,7 @@ static int handle_escape(int * this_buf, int * timeout, int c) {
return 0; return 0;
} }
#ifndef _WIN32
static unsigned int _INTR, _EOF; static unsigned int _INTR, _EOF;
static struct termios old; static struct termios old;
static void get_initial_termios(void) { static void get_initial_termios(void) {
@ -1785,7 +1780,6 @@ static void get_initial_termios(void) {
_INTR = old.c_cc[VINTR]; _INTR = old.c_cc[VINTR];
_EOF = old.c_cc[VEOF]; _EOF = old.c_cc[VEOF];
} }
static void set_unbuffered(void) { static void set_unbuffered(void) {
struct termios new = old; struct termios new = old;
new.c_lflag &= (~ICANON & ~ECHO & ~ISIG); new.c_lflag &= (~ICANON & ~ECHO & ~ISIG);
@ -1795,6 +1789,18 @@ static void set_unbuffered(void) {
static void set_buffered(void) { static void set_buffered(void) {
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &old); tcsetattr(STDOUT_FILENO, TCSAFLUSH, &old);
} }
#else
static unsigned int _INTR = 3;
static unsigned int _EOF = 4;
static void get_initial_termios(void) {
}
static void set_unbuffered(void) {
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_VIRTUAL_TERMINAL_INPUT);
}
static void set_buffered(void) {
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
}
#endif
static int tabbed; static int tabbed;
@ -1910,11 +1916,14 @@ static int read_line(void) {
uint32_t istate = 0; uint32_t istate = 0;
int immediate = 1; int immediate = 1;
#ifndef _WIN32
/* Let's disable this under Windows... */
set_colors(COLOR_ALT_FG, COLOR_ALT_BG); set_colors(COLOR_ALT_FG, COLOR_ALT_BG);
fprintf(stdout, "\033[0m"); /* TODO: This could be retrieved from an envvar */ fprintf(stdout, "\033[0m"); /* TODO: This could be retrieved from an envvar */
for (int i = 0; i < rline_terminal_width - 1; ++i) { for (int i = 0; i < rline_terminal_width - 1; ++i) {
fprintf(stdout, " "); fprintf(stdout, " ");
} }
#endif
if (rline_preload) { if (rline_preload) {
char * c = rline_preload; char * c = rline_preload;
@ -1980,6 +1989,7 @@ static int read_line(void) {
delete_at_cursor(); delete_at_cursor();
immediate = 0; immediate = 0;
break; break;
case 13:
case ENTER_KEY: case ENTER_KEY:
/* Finished */ /* Finished */
loading = 1; loading = 1;

View File

@ -6,7 +6,11 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#ifndef _WIN32
#include <sys/utsname.h> #include <sys/utsname.h>
#else
#include <windows.h>
#endif
#include "../vm.h" #include "../vm.h"
#include "../value.h" #include "../value.h"
@ -21,6 +25,7 @@ extern char ** environ;
* system.uname() * system.uname()
*/ */
static KrkValue krk_uname(int argc, KrkValue argv[]) { static KrkValue krk_uname(int argc, KrkValue argv[]) {
#ifndef _WIN32
struct utsname buf; struct utsname buf;
if (uname(&buf) < 0) return NONE_VAL(); if (uname(&buf) < 0) return NONE_VAL();
@ -35,8 +40,56 @@ static KrkValue krk_uname(int argc, KrkValue argv[]) {
}); });
KRK_RESUME_GC(); KRK_RESUME_GC();
return result; return result;
#else
KRK_PAUSE_GC();
TCHAR buffer[256] = TEXT("");
DWORD dwSize = sizeof(buffer);
GetComputerName(buffer, &dwSize);
OSVERSIONINFOA versionInfo = {0};
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionExA(&versionInfo);
KrkValue release;
if (versionInfo.dwMajorVersion == 10) {
release = OBJECT_VAL(S("10"));
} else if (versionInfo.dwMajorVersion == 6) {
if (versionInfo.dwMinorVersion == 3) {
release = OBJECT_VAL(S("8.1"));
} else if (versionInfo.dwMinorVersion == 2) {
release = OBJECT_VAL(S("8.0"));
} else if (versionInfo.dwMinorVersion == 1) {
release = OBJECT_VAL(S("7"));
} else if (versionInfo.dwMinorVersion == 0) {
release = OBJECT_VAL(S("Vista"));
}
} else {
release = OBJECT_VAL(S("XP or earlier"));
}
char tmp[256];
sprintf(tmp, "%ld", versionInfo.dwBuildNumber);
KrkValue version = OBJECT_VAL(krk_copyString(tmp,strlen(tmp)));
KrkValue machine;
if (sizeof(void *) == 8) {
machine = OBJECT_VAL(S("x64"));
} else {
machine = OBJECT_VAL(S("x86"));
}
KrkValue result = krk_dict_of(5 * 2, (KrkValue[]) {
OBJECT_VAL(S("sysname")), OBJECT_VAL(S("Windows")),
OBJECT_VAL(S("nodename")), OBJECT_VAL(krk_copyString(buffer,dwSize)),
OBJECT_VAL(S("release")), release,
OBJECT_VAL(S("version")), version,
OBJECT_VAL(S("machine")), machine
});
KRK_RESUME_GC();
return result;
#endif
} }
KrkValue krk_os_setenviron(int argc, KrkValue * argv[]) { KrkValue krk_os_setenviron(int argc, KrkValue * argv[]) {

31
vm.c
View File

@ -5,10 +5,6 @@
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifndef STATIC_ONLY
#include <dlfcn.h>
#endif
#include "vm.h" #include "vm.h"
#include "debug.h" #include "debug.h"
#include "memory.h" #include "memory.h"
@ -38,6 +34,24 @@
# define KRK_BUILD_COMPILER "" # define KRK_BUILD_COMPILER ""
#endif #endif
#ifndef _WIN32
# ifndef STATIC_ONLY
# include <dlfcn.h>
# endif
# define PATH_SEP "/"
# define dlRefType void *
# define dlSymType void *
# define dlOpen(fileName) dlopen(fileName, RTLD_NOW)
# define dlSym(dlRef, handlerName) dlsym(dlRef,handlerName)
#else
# include <windows.h>
# define PATH_SEP "\\"
# define dlRefType HINSTANCE
# define dlSymType FARPROC
# define dlOpen(fileName) LoadLibraryA(fileName)
# define dlSym(dlRef, handlerName) GetProcAddress(dlRef, handlerName)
#endif
#define S(c) (krk_copyString(c,sizeof(c)-1)) #define S(c) (krk_copyString(c,sizeof(c)-1))
#define likely(cond) __builtin_expect(!!(cond), 1) #define likely(cond) __builtin_expect(!!(cond), 1)
@ -3247,6 +3261,7 @@ void krk_initVM(int flags) {
krk_attachNamedObject(&vm.system->fields, "builddate", (KrkObj*)S(KRK_BUILD_DATE)); krk_attachNamedObject(&vm.system->fields, "builddate", (KrkObj*)S(KRK_BUILD_DATE));
krk_defineNative(&vm.system->fields, "getsizeof", krk_getsize); krk_defineNative(&vm.system->fields, "getsizeof", krk_getsize);
krk_defineNative(&vm.system->fields, "set_clean_output", krk_setclean); krk_defineNative(&vm.system->fields, "set_clean_output", krk_setclean);
krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(PATH_SEP));
KrkInstance * gcModule = krk_newInstance(vm.moduleClass); KrkInstance * gcModule = krk_newInstance(vm.moduleClass);
krk_attachNamedObject(&vm.modules, "gc", (KrkObj*)gcModule); krk_attachNamedObject(&vm.modules, "gc", (KrkObj*)gcModule);
@ -3698,7 +3713,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs) {
krk_push(AS_LIST(modulePathsInternal)->values[i]); krk_push(AS_LIST(modulePathsInternal)->values[i]);
krk_push(OBJECT_VAL(path)); krk_push(OBJECT_VAL(path));
addObjects(); addObjects();
krk_push(OBJECT_VAL(S("/__init__.krk"))); krk_push(OBJECT_VAL(S(PATH_SEP "__init__.krk")));
addObjects(); addObjects();
fileName = AS_CSTRING(krk_peek(0)); fileName = AS_CSTRING(krk_peek(0));
if (stat(fileName,&statbuf) < 0) { if (stat(fileName,&statbuf) < 0) {
@ -3744,7 +3759,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs) {
char * fileName = AS_CSTRING(krk_peek(0)); char * fileName = AS_CSTRING(krk_peek(0));
if (stat(fileName,&statbuf) < 0) continue; if (stat(fileName,&statbuf) < 0) continue;
void * dlRef = dlopen(fileName, RTLD_NOW); dlRefType dlRef = dlOpen(fileName);
if (!dlRef) { if (!dlRef) {
*moduleOut = NONE_VAL(); *moduleOut = NONE_VAL();
krk_runtimeError(vm.exceptions.importError, krk_runtimeError(vm.exceptions.importError,
@ -3764,7 +3779,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs) {
char * handlerName = AS_CSTRING(krk_peek(0)); char * handlerName = AS_CSTRING(krk_peek(0));
KrkValue (*moduleOnLoad)(KrkString * name); KrkValue (*moduleOnLoad)(KrkString * name);
void * out = dlsym(dlRef, handlerName); dlSymType out = dlSym(dlRef, handlerName);
memcpy(&moduleOnLoad,&out,sizeof(out)); memcpy(&moduleOnLoad,&out,sizeof(out));
if (!moduleOnLoad) { if (!moduleOnLoad) {
@ -3887,7 +3902,7 @@ int krk_doRecursiveModuleLoad(KrkString * name) {
vm.stack[argBase-1] = krk_pop(); vm.stack[argBase-1] = krk_pop();
/* Now concatenate forward slash... */ /* Now concatenate forward slash... */
krk_push(vm.stack[argBase+1]); /* Slash path */ krk_push(vm.stack[argBase+1]); /* Slash path */
krk_push(OBJECT_VAL(S("/"))); krk_push(OBJECT_VAL(S(PATH_SEP)));
addObjects(); addObjects();
vm.stack[argBase+1] = krk_pop(); vm.stack[argBase+1] = krk_pop();
/* And now for the dot... */ /* And now for the dot... */