From 5665fe920310829a999803eb583050b7c9c23647 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 25 Dec 2020 15:10:18 -0400 Subject: [PATCH 01/32] Expanded support for building x-cli --- tools/mcconfig.js | 13 ++++++++++ tools/mcconfig/nmake.x-cli-win.mk | 16 +++++++++--- tools/mcrun/nmake.x-cli-win.mk | 42 +++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 tools/mcrun/nmake.x-cli-win.mk diff --git a/tools/mcconfig.js b/tools/mcconfig.js index 2a5295acf2..bc4a1d3d3e 100644 --- a/tools/mcconfig.js +++ b/tools/mcconfig.js @@ -1095,6 +1095,19 @@ export default class extends Tool { this.createDirectory(this.resourcesPath); } else if (this.platform.startsWith("x-cli-")) { + var folder = "mc", file; + this.createDirectory(this.modulesPath + this.slash + folder); + var source = this.tmpPath + this.slash + "mc.config.js"; + var target = folder + this.slash + "config.xsb"; + this.jsFiles.push({ source, target }); + if (this.preloads.length) + this.preloads.push("mc" + this.slash + "config.xsb"); + file = new ConfigFile(source, this); + file.generate(this); + file = new DefinesFile(this.tmpPath + this.slash + "mc.defines.h", this); + file.generate(this); + this.dataPath = this.resourcesPath = this.tmpPath + this.slash + "resources"; + this.createDirectory(this.resourcesPath); } else { var folder = "mc", file; diff --git a/tools/mcconfig/nmake.x-cli-win.mk b/tools/mcconfig/nmake.x-cli-win.mk index cc6ec420d0..89b82e0870 100644 --- a/tools/mcconfig/nmake.x-cli-win.mk +++ b/tools/mcconfig/nmake.x-cli-win.mk @@ -139,7 +139,7 @@ C_FLAGS = $(XS_C_FLAGS) RC_OPTIONS = /nologo -LINK_LIBRARIES = ws2_32.lib advapi32.lib comctl32.lib comdlg32.lib gdi32.lib kernel32.lib user32.lib Iphlpapi.lib +LINK_LIBRARIES = ws2_32.lib advapi32.lib comctl32.lib comdlg32.lib gdi32.lib kernel32.lib user32.lib Iphlpapi.lib wlanapi.lib LINK_OPTIONS = /incremental:no /machine:I386 /nologo /subsystem:console !IF "$(DEBUG)"=="1" @@ -172,9 +172,9 @@ clean: $(LIB_DIR) : if not exist $(LIB_DIR)\$(NULL) mkdir $(LIB_DIR) -$(BIN_DIR)\$(NAME).exe: $(XS_OBJECTS) $(TMP_DIR)\mc.xs.o $(OBJECTS) - @echo # link $(NAME).exe - link $(LINK_OPTIONS) $(LINK_LIBRARIES) $(XS_OBJECTS) $(TMP_DIR)\mc.xs.o $(OBJECTS) /implib:$(TMP_DIR)\$(NAME).lib /out:$@ +$(BIN_DIR)\$(NAME).exe: $(XS_OBJECTS) $(TMP_DIR)\mc.xs.o $(TMP_DIR)\mc.resources.o $(OBJECTS) + @echo # link $(NAME).exe ($(BIN_DIR)\$(NAME)) + link $(LINK_OPTIONS) $(LINK_LIBRARIES) $(XS_OBJECTS) $(TMP_DIR)\mc.xs.o $(TMP_DIR)\mc.resources.o $(OBJECTS) /implib:$(TMP_DIR)\$(NAME).lib /out:$@ $(XS_OBJECTS) : $(XS_HEADERS) {$(XS_DIR)\sources\}.c{$(LIB_DIR)\}.o: @@ -190,3 +190,11 @@ $(TMP_DIR)\mc.xs.c: $(MODULES) $(MANIFEST) $(XSL) -b $(MODULES_DIR) -o $(TMP_DIR) $(PRELOADS) $(CREATION) $(MODULES) +$(TMP_DIR)\mc.resources.o: $(TMP_DIR)\mc.resources.c $(HEADERS) + cl $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) $(TMP_DIR)\mc.resources.c /Fo$@ + +$(TMP_DIR)\mc.resources.c: $(DATA) $(RESOURCES) $(MANIFEST) + @echo # mcrez resources + $(MCREZ) <. +# + +!IF "$(VERBOSE)"=="1" +!CMDSWITCHES -S +!ELSE +!CMDSWITCHES +S +!ENDIF + +BUILDCLUT = $(BUILD_DIR)\bin\win\release\buildclut +COMPRESSBMF = $(BUILD_DIR)\bin\win\release\compressbmf +IMAGE2CS = $(BUILD_DIR)\bin\win\release\image2cs +MCLOCAL = $(BUILD_DIR)\bin\win\release\mclocal +MCREZ = $(BUILD_DIR)\bin\win\release\mcrez +PNG2BMP = $(BUILD_DIR)\bin\win\release\png2bmp +RLE4ENCODE = $(BUILD_DIR)\bin\win\release\rle4encode +WAV2MAUD = $(BUILD_DIR)\bin\win\release\wav2maud +XSC = $(BUILD_DIR)\bin\win\release\xsc +XSL = $(BUILD_DIR)\bin\win\release\xsl + +all: $(BIN_DIR)\mc.xsa + @echo # Mod: $(BIN_DIR)\mc.xsa + +$(BIN_DIR)\mc.xsa: $(DATA) $(MODULES) $(RESOURCES) + @echo # xsl mc.xsa + $(XSL) -a -b $(MODULES_DIR) -n $(DOT_SIGNATURE) -o $(BIN_DIR) $(DATA) $(MODULES) $(RESOURCES) From 199eb405ec4fd7e1b6c681aef320d50de2bf68ae Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 25 Dec 2020 15:10:44 -0400 Subject: [PATCH 02/32] Added manifest support for x-cli-win --- examples/manifest_net.json | 16 ++++++++++++++++ modules/files/file/manifest.json | 10 ++++++++++ modules/files/preference/manifest.json | 7 +++++++ modules/network/wifi/manifest.json | 7 +++++++ 4 files changed, 40 insertions(+) diff --git a/examples/manifest_net.json b/examples/manifest_net.json index 39c506fa25..a713af8b5d 100644 --- a/examples/manifest_net.json +++ b/examples/manifest_net.json @@ -83,6 +83,22 @@ "net" ] }, + "x-cli-win": { + "modules": { + "*": [ + "$(MODULES)/network/socket/*", + "$(MODULES)/network/socket/win/*", + "$(MODULES)/network/net/net", + "$(MODULES)/network/net/win/*", + "$(MODULES)/network/sntp/*" + ] + }, + "preload": [ + "socket", + "sntp", + "net" + ] + }, "qca4020": { "modules": { "*": [ diff --git a/modules/files/file/manifest.json b/modules/files/file/manifest.json index d1d30cd7bb..7b951d1da5 100644 --- a/modules/files/file/manifest.json +++ b/modules/files/file/manifest.json @@ -54,6 +54,16 @@ } } }, + "x-cli-win": { + "modules": { + "*": "$(MODULES)/files/file/win/*" + }, + "config": { + "file": { + "root": "./" + } + } + }, "lin": { "modules": { "*": "$(MODULES)/files/file/lin/*" diff --git a/modules/files/preference/manifest.json b/modules/files/preference/manifest.json index d910c7b51c..35954e7ed8 100644 --- a/modules/files/preference/manifest.json +++ b/modules/files/preference/manifest.json @@ -42,6 +42,13 @@ "$(MODULES)/files/preference/win/*" ] } + }, + "x-cli-win": { + "modules": { + "*": [ + "$(MODULES)/files/preference/win/*" + ] + } } } } diff --git a/modules/network/wifi/manifest.json b/modules/network/wifi/manifest.json index 514a5c3a84..6b670940cc 100644 --- a/modules/network/wifi/manifest.json +++ b/modules/network/wifi/manifest.json @@ -37,6 +37,13 @@ ] } }, + "x-cli-win": { + "modules": { + "*": [ + "$(MODULES)/network/wifi/sim/*" + ] + } + }, "qca4020": { "modules": { "*": [ From cb1273b851712e1e154bc60a590c3906770af7ea Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 25 Dec 2020 15:11:14 -0400 Subject: [PATCH 03/32] Added x-cli-win main cli --- contributed/cli/README.md | 43 ++++++ contributed/cli/manifest.json | 12 ++ contributed/cli/x-cli-win/machine.c | 223 ++++++++++++++++++++++++++++ contributed/cli/x-cli-win/machine.h | 24 +++ contributed/cli/x-cli-win/main.c | 130 ++++++++++++++++ 5 files changed, 432 insertions(+) create mode 100644 contributed/cli/README.md create mode 100644 contributed/cli/manifest.json create mode 100644 contributed/cli/x-cli-win/machine.c create mode 100644 contributed/cli/x-cli-win/machine.h create mode 100644 contributed/cli/x-cli-win/main.c diff --git a/contributed/cli/README.md b/contributed/cli/README.md new file mode 100644 index 0000000000..46d71c99eb --- /dev/null +++ b/contributed/cli/README.md @@ -0,0 +1,43 @@ +# Command line (cli) controller + +Moddable is able to provide command line programs using the `x-cli-` platform type, including `x-cli-win` for +Windows, `x-cli-mac` for Mac, and `x-cli-lin` for Linux. When using this code, you are normally responsible for +creating your own main code and support services for moddable. This package provides an implementation of the command +line interfaces for Moddable, including support for the event loop and host/mod loading. + +## Configuring the manifest + +To have your Moddable program use this command line interface, you simply update the `include` section to add the `cli` +manifest file: + +``` +"include": [ + ... other includes ... + "$(MODDABLE)/contributed/cli/manifest.json" +], +``` + +## Running your program + +When you build, such as `mcconfig -m -d -p x-cli-win`, the resulting program will be a native app (such as `.exe` on +windows, or `.app` on mac). If you run that program with no command line arguments, the default exported `main` +function will be called. The code will continue to operate, including support for Timer and other async services. If +you need to terminate the app under control of the program, use: + +``` +function abort(status) @ "fxAbort"; + +fxAbort(status); // status is the exit code the program will terminate with +``` + +## Using mods + +It you specify a path to a mod file (`.xsa` file, built with `mcrun`) as the first argument to the program, it will be +loaded and symbols resolved before the `main` exported function is called. This is slightly different than how the +microcontrollers consume mods (from the flash `xs` partition, upon reboot) or how the simulators consume mods (provided +via the `mcrun` program while a host waits for the module to be presented), but the resulting functionality remains the same. + +## Using the debugger and instrumentation + +Full support for the debugger and instrumentation is included, and it should behave the same as using other platform +types. Instrumentation is updated once per second. \ No newline at end of file diff --git a/contributed/cli/manifest.json b/contributed/cli/manifest.json new file mode 100644 index 0000000000..4eccd0d578 --- /dev/null +++ b/contributed/cli/manifest.json @@ -0,0 +1,12 @@ +{ + "platforms": { + "x-cli-win": { + "modules": { + "*": [ + "./x-cli-win/main", + "./x-cli-win/machine" + ] + } + } + } +} \ No newline at end of file diff --git a/contributed/cli/x-cli-win/machine.c b/contributed/cli/x-cli-win/machine.c new file mode 100644 index 0000000000..368e8bebf6 --- /dev/null +++ b/contributed/cli/x-cli-win/machine.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2016-2020 Moddable Tech, Inc. and Chris Midgley + * + * This file is part of the Moddable SDK Runtime. + * + * The Moddable SDK Runtime is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Runtime is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the Moddable SDK Runtime. If not, see . + * + */ + +/* + This file implements services for the x-cli-win platform to start/stop the XS virtual machine, provide loading of + archives (mods), and handling of instrumentation updates. +*/ + +#include "xsAll.h" +#include "mc.xs.h" + +HANDLE archiveFile = INVALID_HANDLE_VALUE; +HANDLE archiveMapping = INVALID_HANDLE_VALUE; +static txMachine root; +txMachine* machine = &root; + + +/* + Service used by fxMapArchive to read a section of the archive (mod) from memory +*/ +xsBooleanValue fxArchiveRead(void* src, size_t offset, void* buffer, size_t size) { + c_memcpy(buffer, ((txU1*)src) + offset, size); + return 1; +} + +/* + Service used by fxMapArchive to write a section of the archive (mod) in memory +*/ +xsBooleanValue fxArchiveWrite(void* dst, size_t offset, void* buffer, size_t size) { + c_memcpy(((txU1*)dst) + offset, buffer, size); + return 1; +} + +/* + Windows specific implementation to map an archive (mod) into memory. Accepts the path to the + archive, and returns either a pointer to the memory mapped image, or NULL if there was a failure during the loading + of the file. +*/ +void *loadArchive(char *archivePath) { + if (archivePath[0]) { + DWORD size; + archiveFile = CreateFile(archivePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (archiveFile == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to open archive %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + size = GetFileSize(archiveFile, &size); + if (size == INVALID_FILE_SIZE) { + fprintf(stderr, "Failed to get file size for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + archiveMapping = CreateFileMapping(archiveFile, NULL, PAGE_READWRITE, 0, (SIZE_T)size, NULL); + if (archiveMapping == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to create file mapping for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + void *memArchive = MapViewOfFile(archiveMapping, FILE_MAP_WRITE, 0, 0, (SIZE_T)size); + if (memArchive == NULL) { + fprintf(stderr, "Failed to map view of file for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + return memArchive; + } + return NULL; +} + +/* + Callback function when the debugger is executed (see machine->onBreak). Updates the instrumentation so + breakpoints have accurate instrumentation just prior to stopping. +*/ +void debugBreak(xsMachine* the, uint8_t stop) +{ +#ifdef mxInstrument + if (stop) { + // fxCollectGarbage(the); + // the->garbageCollectionCount -= 1; + fxSampleInstrumentation(the, 0, NULL); + } +#endif +} + +/* + Starts up an XS machine, including loading and mapping the archive (mod) and calling the exported + function "main". +*/ +int startMachine(char *archivePath) { + int error = 0; + txPreparation* preparation = xsPreparation(); + void *memArchive = NULL; // memory mapped instance of the mod (archive) + void *archive = NULL; // XS symbol-mapped archive + + // set up the XS VM + c_memset(machine, 0, sizeof(txMachine)); + machine->preparation = preparation; + machine->keyArray = preparation->keys; + machine->keyCount = (txID)preparation->keyCount + (txID)preparation->creation.keyCount; + machine->keyIndex = (txID)preparation->keyCount; + machine->nameModulo = preparation->nameModulo; + machine->nameTable = preparation->names; + machine->symbolModulo = preparation->symbolModulo; + machine->symbolTable = preparation->symbols; + + machine->stack = &preparation->stack[0]; + machine->stackBottom = &preparation->stack[0]; + machine->stackTop = &preparation->stack[preparation->stackCount]; + + machine->firstHeap = &preparation->heap[0]; + machine->freeHeap = &preparation->heap[preparation->heapCount - 1]; + machine->aliasCount = (txID)preparation->aliasCount; + + machine->onBreak = debugBreak; + + // memory map the archive using the first argument on the command line + if (archivePath) { + memArchive = loadArchive(archivePath); + } + + // map the symbols for the mod ("archive") + if (memArchive) { + archive = fxMapArchive(preparation, memArchive, memArchive, 4 * 1024, fxArchiveRead, fxArchiveWrite); + if (!archive) { + fprintf(stderr, "Failed to map the archive; continuing with no archive\n"); + } + } + + // instantiate the VM + machine = fxPrepareMachine(NULL, preparation, "machine", NULL, archive); + if (!machine) { + fprintf(stderr, "Failed to instantiate the VM\n"); + return 1; + } + + + // set up the stack context for XS + xsBeginHost(machine); + { + xsVars(1); + +#ifdef mxInstrument + // send the instrumentation headers, only if the debugger is connected + if (fxIsConnected(the)) + fxDescribeInstrumentation(machine, 0, NULL, NULL); + + // send the initial instrumentation data, only if the debugger is connected + if (fxIsConnected(the)) + fxSampleInstrumentation(the, 0, NULL); +#endif + { + // attempt to locate the "main" export from the host, and call it's function to start it + xsTry { + xsVar(0) = xsAwaitImport("main", XS_IMPORT_DEFAULT); + if (xsTest(xsVar(0))) { + if (xsIsInstanceOf(xsVar(0), xsFunctionPrototype)) { + xsCallFunction0(xsVar(0), xsGlobal); + } + } + } + xsCatch { + xsStringValue message = xsToString(xsException); + fprintf(stderr, "Uncaught error from VM: %s\n", message); + error = 1; + } + } + } + xsEndHost(the); + return error; +} + +/* + Terminates a running XS machine +*/ +void endMachine() { + xsDeleteMachine(machine); +} + +/* + Updates instrumentation (debugging statistics) for a running XS machine +*/ +void instrumentMachine() { +#ifdef mxDebug + xsBeginHost(machine); + { + // is the debugger connected? If not, skip to avoid console output + if (fxIsConnected(the)) + fxSampleInstrumentation(the, 0, NULL); + } + xsEndHost(the); +#endif +} + +/* + End point for XS to terminate execution +*/ +void fxAbort(xsMachine* the, int status) { + if (status == xsNotEnoughMemoryExit) + fprintf(stderr, "Abort: not enough memory\n"); + else if (status == xsStackOverflowExit) + fprintf(stderr, "Abort: stack overflow\n"); + else if (status == xsDeadStripExit) + fprintf(stderr, "Abort: dead strip\n"); + else if (status == xsUnhandledExceptionExit) + fprintf(stderr, "Abort: unhandled exception\n"); + else if (status != 0) + fprintf(stderr, "Abort: Error code %d\n", status); + exit(status); +} diff --git a/contributed/cli/x-cli-win/machine.h b/contributed/cli/x-cli-win/machine.h new file mode 100644 index 0000000000..ccfc881aa6 --- /dev/null +++ b/contributed/cli/x-cli-win/machine.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 Chris Midgley + * + * This file is part of the Moddable SDK Tools. + * + * The Moddable SDK Tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Moddable SDK Tools. If not, see . + * + */ + +int startMachine(char *archivePath); +void endMachine(); +void instrumentMachine(); + diff --git a/contributed/cli/x-cli-win/main.c b/contributed/cli/x-cli-win/main.c new file mode 100644 index 0000000000..2aae632057 --- /dev/null +++ b/contributed/cli/x-cli-win/main.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2020 Chris Midgley + * + * This file is part of the Moddable SDK Tools. + * + * The Moddable SDK Tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Moddable SDK Tools. If not, see . + * + */ + +/* + This file implements a x-cli-win platform for Moddable that supports an event loop and dynamically loaded + archives (mods). It implements the C main function, sets up XS machine and starts a Windows message pump. + Upon a WM_CLOSE message (which is intercepted and sent upon ^C) it cleanly shuts down the XS machine. It also + maintains the instrumentation updates, using a timer, on a once/second interval. +*/ + +#include "xsAll.h" +#include +#include +#include +#include +#include "machine.h" +#include "sysinfoapi.h" + +unsigned int messagePumpThreadId = 0; // thread ID of the thread running the windows message pump +#ifdef mxInstrument +#define WM_APP_INSTRUMENTATION (WM_APP + 1) // ID of our private instrumentation message + +static VOID CALLBACK sendInstrumentationMessage(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { + PostThreadMessage(messagePumpThreadId, WM_APP_INSTRUMENTATION, 0, 0); +} +#endif + + +/* + Message pump that manages the XS virtual machine. The machine is started up, then the Windows message + pump is executed allow for modules such as Timer to be used. Also maintains instrumentation to xsbug once + per second, triggered by the WM_APP_INSTRUMENTATION message from a timer. Shuts down the VM when a WM_CLOSE + message is received, and signals completion using the terminateEvent event. +*/ +void messagePump(char *pathToMod) +{ + MSG msg; + + // save away our thread ID - this is done so that the ^C interception can send us a WM_CLOSE message + messagePumpThreadId = GetCurrentThreadId(); + + // start up our VM + int error = startMachine(pathToMod); + + // set up a timer for the instrumentation +#ifdef mxInstrument + SetTimer(NULL, 1, 1000, sendInstrumentationMessage); +#endif + + // process the windows message loop until terminated + while( GetMessage(&msg, NULL, 0, 0) > 0 ) { +#ifdef mxInstrument + if (msg.message == WM_APP_INSTRUMENTATION) { + // make sure we don't issue instrumentation more often than once/second - if the host gets busy, a + // bunch of messages can be queued up, and this drops the extra ones on the floor + static DWORD instrumentTime = 0; + DWORD currentTime = GetTickCount(); + + if (instrumentTime < currentTime) { + instrumentTime = currentTime + 1000; + instrumentMachine(); + } + + continue; + } +#endif + + // do we need to shut down? + if (msg.message == WM_CLOSE) + break; + + // go ahead and let the message get dispatched + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // done - end our XS machine + endMachine(); +} + +/* + Handler for intercepting the ctrl-C shutdown of the process, and sends the WM_CLOSE message so the message pump can + initiate a shutdown +*/ +BOOL WINAPI ctrlHandler(_In_ DWORD dwCtrlType) { + switch (dwCtrlType) + { + case CTRL_C_EVENT: + PostThreadMessage(messagePumpThreadId, WM_CLOSE, 0, 0); + + return TRUE; + default: + // Pass signal on to the next handler + return FALSE; + } +} + + +/* + main - accepts a single optional command line argument that is the path to a mod to load + + Sets a ^C handler (for clearn shutdown) and starts up the VM and message pump +*/ +int main(int argc, char* argv[]) { + + // take control over ^C handling + SetConsoleCtrlHandler(ctrlHandler, TRUE); + + // start up the XS VM and run the message pump + messagePump((argc > 1) ? argv[1] : NULL); + + return 0; +} From 4b73560ecd46bb87fdc82152b6638cca9a11be04 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 25 Dec 2020 15:55:51 -0400 Subject: [PATCH 04/32] Manifest support for x-cli-lin and x-cli-mac --- contributed/cli/manifest.json | 16 ++++++++++++++ examples/manifest_net.json | 30 ++++++++++++++++++++++++++ modules/files/file/manifest.json | 10 +++++++++ modules/files/preference/manifest.json | 7 ++++++ modules/network/wifi/manifest.json | 14 ++++++++++++ 5 files changed, 77 insertions(+) diff --git a/contributed/cli/manifest.json b/contributed/cli/manifest.json index 4eccd0d578..b5093502ff 100644 --- a/contributed/cli/manifest.json +++ b/contributed/cli/manifest.json @@ -7,6 +7,22 @@ "./x-cli-win/machine" ] } + }, + "x-cli-mac": { + "modules": { + "*": [ + "./x-cli-mac/main" + "./x-cli-mac/machine" + ] + } + }, + "x-cli-lin": { + "modules": { + "*": [ + "./x-cli-lin/main", + "./x-cli-lin/machine" + ] + } } } } \ No newline at end of file diff --git a/examples/manifest_net.json b/examples/manifest_net.json index a713af8b5d..f70af010ea 100644 --- a/examples/manifest_net.json +++ b/examples/manifest_net.json @@ -99,6 +99,36 @@ "net" ] }, + "x-cli-mac": { + "modules": { + "*": [ + "$(MODULES)/network/socket/*", + "$(MODULES)/network/socket/mac/*", + "$(MODULES)/network/net/net", + "$(MODULES)/network/net/mac/*", + "$(MODULES)/network/sntp/*" + ] + }, + "preload": [ + "socket", + "sntp", + "net" + ] + }, + "x-cli-lin": { + "modules": { + "*": [ + "$(MODULES)/network/socket/*", + "$(MODULES)/network/socket/lin/*", + "$(MODULES)/network/net/net", + "$(MODULES)/network/net/lin/*" + ] + }, + "preload": [ + "socket", + "net" + ] + }, "qca4020": { "modules": { "*": [ diff --git a/modules/files/file/manifest.json b/modules/files/file/manifest.json index 7b951d1da5..15f5ae9160 100644 --- a/modules/files/file/manifest.json +++ b/modules/files/file/manifest.json @@ -74,6 +74,16 @@ } } }, + "x-cli-lin": { + "modules": { + "*": "$(MODULES)/files/file/lin/*" + }, + "config": { + "file": { + "root": "/tmp/" + } + } + }, "qca4020": { "modules": { "*": "$(MODULES)/files/file/qca4020/*" diff --git a/modules/files/preference/manifest.json b/modules/files/preference/manifest.json index 35954e7ed8..4feaf60a07 100644 --- a/modules/files/preference/manifest.json +++ b/modules/files/preference/manifest.json @@ -36,6 +36,13 @@ ] } }, + "x-cli-mac": { + "modules": { + "*": [ + "$(MODULES)/files/preference/mac/*" + ] + } + }, "win": { "modules": { "*": [ diff --git a/modules/network/wifi/manifest.json b/modules/network/wifi/manifest.json index 6b670940cc..b66bcdc4d8 100644 --- a/modules/network/wifi/manifest.json +++ b/modules/network/wifi/manifest.json @@ -23,6 +23,13 @@ ] } }, + "x-cli-lin": { + "modules": { + "*": [ + "$(MODULES)/network/wifi/sim/*" + ] + } + }, "mac": { "modules": { "*": [ @@ -30,6 +37,13 @@ ] } }, + "x-cli-mac": { + "modules": { + "*": [ + "$(MODULES)/network/wifi/sim/*" + ] + } + }, "win": { "modules": { "*": [ From 7425c8aa31e699eff7339d905685e4002b126e5f Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 26 Dec 2020 07:49:21 -0400 Subject: [PATCH 05/32] initial setup for mac and lin --- contributed/cli/manifest.json | 2 +- contributed/cli/x-cli-lin/machine.c | 223 ++++++++++++++++++++++++++++ contributed/cli/x-cli-lin/machine.h | 24 +++ contributed/cli/x-cli-lin/main.c | 130 ++++++++++++++++ contributed/cli/x-cli-mac/machine.c | 223 ++++++++++++++++++++++++++++ contributed/cli/x-cli-mac/machine.h | 24 +++ contributed/cli/x-cli-mac/main.c | 130 ++++++++++++++++ 7 files changed, 755 insertions(+), 1 deletion(-) create mode 100644 contributed/cli/x-cli-lin/machine.c create mode 100644 contributed/cli/x-cli-lin/machine.h create mode 100644 contributed/cli/x-cli-lin/main.c create mode 100644 contributed/cli/x-cli-mac/machine.c create mode 100644 contributed/cli/x-cli-mac/machine.h create mode 100644 contributed/cli/x-cli-mac/main.c diff --git a/contributed/cli/manifest.json b/contributed/cli/manifest.json index b5093502ff..3290a4e3d6 100644 --- a/contributed/cli/manifest.json +++ b/contributed/cli/manifest.json @@ -11,7 +11,7 @@ "x-cli-mac": { "modules": { "*": [ - "./x-cli-mac/main" + "./x-cli-mac/main", "./x-cli-mac/machine" ] } diff --git a/contributed/cli/x-cli-lin/machine.c b/contributed/cli/x-cli-lin/machine.c new file mode 100644 index 0000000000..368e8bebf6 --- /dev/null +++ b/contributed/cli/x-cli-lin/machine.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2016-2020 Moddable Tech, Inc. and Chris Midgley + * + * This file is part of the Moddable SDK Runtime. + * + * The Moddable SDK Runtime is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Runtime is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the Moddable SDK Runtime. If not, see . + * + */ + +/* + This file implements services for the x-cli-win platform to start/stop the XS virtual machine, provide loading of + archives (mods), and handling of instrumentation updates. +*/ + +#include "xsAll.h" +#include "mc.xs.h" + +HANDLE archiveFile = INVALID_HANDLE_VALUE; +HANDLE archiveMapping = INVALID_HANDLE_VALUE; +static txMachine root; +txMachine* machine = &root; + + +/* + Service used by fxMapArchive to read a section of the archive (mod) from memory +*/ +xsBooleanValue fxArchiveRead(void* src, size_t offset, void* buffer, size_t size) { + c_memcpy(buffer, ((txU1*)src) + offset, size); + return 1; +} + +/* + Service used by fxMapArchive to write a section of the archive (mod) in memory +*/ +xsBooleanValue fxArchiveWrite(void* dst, size_t offset, void* buffer, size_t size) { + c_memcpy(((txU1*)dst) + offset, buffer, size); + return 1; +} + +/* + Windows specific implementation to map an archive (mod) into memory. Accepts the path to the + archive, and returns either a pointer to the memory mapped image, or NULL if there was a failure during the loading + of the file. +*/ +void *loadArchive(char *archivePath) { + if (archivePath[0]) { + DWORD size; + archiveFile = CreateFile(archivePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (archiveFile == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to open archive %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + size = GetFileSize(archiveFile, &size); + if (size == INVALID_FILE_SIZE) { + fprintf(stderr, "Failed to get file size for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + archiveMapping = CreateFileMapping(archiveFile, NULL, PAGE_READWRITE, 0, (SIZE_T)size, NULL); + if (archiveMapping == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to create file mapping for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + void *memArchive = MapViewOfFile(archiveMapping, FILE_MAP_WRITE, 0, 0, (SIZE_T)size); + if (memArchive == NULL) { + fprintf(stderr, "Failed to map view of file for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + return memArchive; + } + return NULL; +} + +/* + Callback function when the debugger is executed (see machine->onBreak). Updates the instrumentation so + breakpoints have accurate instrumentation just prior to stopping. +*/ +void debugBreak(xsMachine* the, uint8_t stop) +{ +#ifdef mxInstrument + if (stop) { + // fxCollectGarbage(the); + // the->garbageCollectionCount -= 1; + fxSampleInstrumentation(the, 0, NULL); + } +#endif +} + +/* + Starts up an XS machine, including loading and mapping the archive (mod) and calling the exported + function "main". +*/ +int startMachine(char *archivePath) { + int error = 0; + txPreparation* preparation = xsPreparation(); + void *memArchive = NULL; // memory mapped instance of the mod (archive) + void *archive = NULL; // XS symbol-mapped archive + + // set up the XS VM + c_memset(machine, 0, sizeof(txMachine)); + machine->preparation = preparation; + machine->keyArray = preparation->keys; + machine->keyCount = (txID)preparation->keyCount + (txID)preparation->creation.keyCount; + machine->keyIndex = (txID)preparation->keyCount; + machine->nameModulo = preparation->nameModulo; + machine->nameTable = preparation->names; + machine->symbolModulo = preparation->symbolModulo; + machine->symbolTable = preparation->symbols; + + machine->stack = &preparation->stack[0]; + machine->stackBottom = &preparation->stack[0]; + machine->stackTop = &preparation->stack[preparation->stackCount]; + + machine->firstHeap = &preparation->heap[0]; + machine->freeHeap = &preparation->heap[preparation->heapCount - 1]; + machine->aliasCount = (txID)preparation->aliasCount; + + machine->onBreak = debugBreak; + + // memory map the archive using the first argument on the command line + if (archivePath) { + memArchive = loadArchive(archivePath); + } + + // map the symbols for the mod ("archive") + if (memArchive) { + archive = fxMapArchive(preparation, memArchive, memArchive, 4 * 1024, fxArchiveRead, fxArchiveWrite); + if (!archive) { + fprintf(stderr, "Failed to map the archive; continuing with no archive\n"); + } + } + + // instantiate the VM + machine = fxPrepareMachine(NULL, preparation, "machine", NULL, archive); + if (!machine) { + fprintf(stderr, "Failed to instantiate the VM\n"); + return 1; + } + + + // set up the stack context for XS + xsBeginHost(machine); + { + xsVars(1); + +#ifdef mxInstrument + // send the instrumentation headers, only if the debugger is connected + if (fxIsConnected(the)) + fxDescribeInstrumentation(machine, 0, NULL, NULL); + + // send the initial instrumentation data, only if the debugger is connected + if (fxIsConnected(the)) + fxSampleInstrumentation(the, 0, NULL); +#endif + { + // attempt to locate the "main" export from the host, and call it's function to start it + xsTry { + xsVar(0) = xsAwaitImport("main", XS_IMPORT_DEFAULT); + if (xsTest(xsVar(0))) { + if (xsIsInstanceOf(xsVar(0), xsFunctionPrototype)) { + xsCallFunction0(xsVar(0), xsGlobal); + } + } + } + xsCatch { + xsStringValue message = xsToString(xsException); + fprintf(stderr, "Uncaught error from VM: %s\n", message); + error = 1; + } + } + } + xsEndHost(the); + return error; +} + +/* + Terminates a running XS machine +*/ +void endMachine() { + xsDeleteMachine(machine); +} + +/* + Updates instrumentation (debugging statistics) for a running XS machine +*/ +void instrumentMachine() { +#ifdef mxDebug + xsBeginHost(machine); + { + // is the debugger connected? If not, skip to avoid console output + if (fxIsConnected(the)) + fxSampleInstrumentation(the, 0, NULL); + } + xsEndHost(the); +#endif +} + +/* + End point for XS to terminate execution +*/ +void fxAbort(xsMachine* the, int status) { + if (status == xsNotEnoughMemoryExit) + fprintf(stderr, "Abort: not enough memory\n"); + else if (status == xsStackOverflowExit) + fprintf(stderr, "Abort: stack overflow\n"); + else if (status == xsDeadStripExit) + fprintf(stderr, "Abort: dead strip\n"); + else if (status == xsUnhandledExceptionExit) + fprintf(stderr, "Abort: unhandled exception\n"); + else if (status != 0) + fprintf(stderr, "Abort: Error code %d\n", status); + exit(status); +} diff --git a/contributed/cli/x-cli-lin/machine.h b/contributed/cli/x-cli-lin/machine.h new file mode 100644 index 0000000000..ccfc881aa6 --- /dev/null +++ b/contributed/cli/x-cli-lin/machine.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 Chris Midgley + * + * This file is part of the Moddable SDK Tools. + * + * The Moddable SDK Tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Moddable SDK Tools. If not, see . + * + */ + +int startMachine(char *archivePath); +void endMachine(); +void instrumentMachine(); + diff --git a/contributed/cli/x-cli-lin/main.c b/contributed/cli/x-cli-lin/main.c new file mode 100644 index 0000000000..2aae632057 --- /dev/null +++ b/contributed/cli/x-cli-lin/main.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2020 Chris Midgley + * + * This file is part of the Moddable SDK Tools. + * + * The Moddable SDK Tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Moddable SDK Tools. If not, see . + * + */ + +/* + This file implements a x-cli-win platform for Moddable that supports an event loop and dynamically loaded + archives (mods). It implements the C main function, sets up XS machine and starts a Windows message pump. + Upon a WM_CLOSE message (which is intercepted and sent upon ^C) it cleanly shuts down the XS machine. It also + maintains the instrumentation updates, using a timer, on a once/second interval. +*/ + +#include "xsAll.h" +#include +#include +#include +#include +#include "machine.h" +#include "sysinfoapi.h" + +unsigned int messagePumpThreadId = 0; // thread ID of the thread running the windows message pump +#ifdef mxInstrument +#define WM_APP_INSTRUMENTATION (WM_APP + 1) // ID of our private instrumentation message + +static VOID CALLBACK sendInstrumentationMessage(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { + PostThreadMessage(messagePumpThreadId, WM_APP_INSTRUMENTATION, 0, 0); +} +#endif + + +/* + Message pump that manages the XS virtual machine. The machine is started up, then the Windows message + pump is executed allow for modules such as Timer to be used. Also maintains instrumentation to xsbug once + per second, triggered by the WM_APP_INSTRUMENTATION message from a timer. Shuts down the VM when a WM_CLOSE + message is received, and signals completion using the terminateEvent event. +*/ +void messagePump(char *pathToMod) +{ + MSG msg; + + // save away our thread ID - this is done so that the ^C interception can send us a WM_CLOSE message + messagePumpThreadId = GetCurrentThreadId(); + + // start up our VM + int error = startMachine(pathToMod); + + // set up a timer for the instrumentation +#ifdef mxInstrument + SetTimer(NULL, 1, 1000, sendInstrumentationMessage); +#endif + + // process the windows message loop until terminated + while( GetMessage(&msg, NULL, 0, 0) > 0 ) { +#ifdef mxInstrument + if (msg.message == WM_APP_INSTRUMENTATION) { + // make sure we don't issue instrumentation more often than once/second - if the host gets busy, a + // bunch of messages can be queued up, and this drops the extra ones on the floor + static DWORD instrumentTime = 0; + DWORD currentTime = GetTickCount(); + + if (instrumentTime < currentTime) { + instrumentTime = currentTime + 1000; + instrumentMachine(); + } + + continue; + } +#endif + + // do we need to shut down? + if (msg.message == WM_CLOSE) + break; + + // go ahead and let the message get dispatched + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // done - end our XS machine + endMachine(); +} + +/* + Handler for intercepting the ctrl-C shutdown of the process, and sends the WM_CLOSE message so the message pump can + initiate a shutdown +*/ +BOOL WINAPI ctrlHandler(_In_ DWORD dwCtrlType) { + switch (dwCtrlType) + { + case CTRL_C_EVENT: + PostThreadMessage(messagePumpThreadId, WM_CLOSE, 0, 0); + + return TRUE; + default: + // Pass signal on to the next handler + return FALSE; + } +} + + +/* + main - accepts a single optional command line argument that is the path to a mod to load + + Sets a ^C handler (for clearn shutdown) and starts up the VM and message pump +*/ +int main(int argc, char* argv[]) { + + // take control over ^C handling + SetConsoleCtrlHandler(ctrlHandler, TRUE); + + // start up the XS VM and run the message pump + messagePump((argc > 1) ? argv[1] : NULL); + + return 0; +} diff --git a/contributed/cli/x-cli-mac/machine.c b/contributed/cli/x-cli-mac/machine.c new file mode 100644 index 0000000000..368e8bebf6 --- /dev/null +++ b/contributed/cli/x-cli-mac/machine.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2016-2020 Moddable Tech, Inc. and Chris Midgley + * + * This file is part of the Moddable SDK Runtime. + * + * The Moddable SDK Runtime is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Runtime is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the Moddable SDK Runtime. If not, see . + * + */ + +/* + This file implements services for the x-cli-win platform to start/stop the XS virtual machine, provide loading of + archives (mods), and handling of instrumentation updates. +*/ + +#include "xsAll.h" +#include "mc.xs.h" + +HANDLE archiveFile = INVALID_HANDLE_VALUE; +HANDLE archiveMapping = INVALID_HANDLE_VALUE; +static txMachine root; +txMachine* machine = &root; + + +/* + Service used by fxMapArchive to read a section of the archive (mod) from memory +*/ +xsBooleanValue fxArchiveRead(void* src, size_t offset, void* buffer, size_t size) { + c_memcpy(buffer, ((txU1*)src) + offset, size); + return 1; +} + +/* + Service used by fxMapArchive to write a section of the archive (mod) in memory +*/ +xsBooleanValue fxArchiveWrite(void* dst, size_t offset, void* buffer, size_t size) { + c_memcpy(((txU1*)dst) + offset, buffer, size); + return 1; +} + +/* + Windows specific implementation to map an archive (mod) into memory. Accepts the path to the + archive, and returns either a pointer to the memory mapped image, or NULL if there was a failure during the loading + of the file. +*/ +void *loadArchive(char *archivePath) { + if (archivePath[0]) { + DWORD size; + archiveFile = CreateFile(archivePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (archiveFile == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to open archive %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + size = GetFileSize(archiveFile, &size); + if (size == INVALID_FILE_SIZE) { + fprintf(stderr, "Failed to get file size for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + archiveMapping = CreateFileMapping(archiveFile, NULL, PAGE_READWRITE, 0, (SIZE_T)size, NULL); + if (archiveMapping == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to create file mapping for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + void *memArchive = MapViewOfFile(archiveMapping, FILE_MAP_WRITE, 0, 0, (SIZE_T)size); + if (memArchive == NULL) { + fprintf(stderr, "Failed to map view of file for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + return memArchive; + } + return NULL; +} + +/* + Callback function when the debugger is executed (see machine->onBreak). Updates the instrumentation so + breakpoints have accurate instrumentation just prior to stopping. +*/ +void debugBreak(xsMachine* the, uint8_t stop) +{ +#ifdef mxInstrument + if (stop) { + // fxCollectGarbage(the); + // the->garbageCollectionCount -= 1; + fxSampleInstrumentation(the, 0, NULL); + } +#endif +} + +/* + Starts up an XS machine, including loading and mapping the archive (mod) and calling the exported + function "main". +*/ +int startMachine(char *archivePath) { + int error = 0; + txPreparation* preparation = xsPreparation(); + void *memArchive = NULL; // memory mapped instance of the mod (archive) + void *archive = NULL; // XS symbol-mapped archive + + // set up the XS VM + c_memset(machine, 0, sizeof(txMachine)); + machine->preparation = preparation; + machine->keyArray = preparation->keys; + machine->keyCount = (txID)preparation->keyCount + (txID)preparation->creation.keyCount; + machine->keyIndex = (txID)preparation->keyCount; + machine->nameModulo = preparation->nameModulo; + machine->nameTable = preparation->names; + machine->symbolModulo = preparation->symbolModulo; + machine->symbolTable = preparation->symbols; + + machine->stack = &preparation->stack[0]; + machine->stackBottom = &preparation->stack[0]; + machine->stackTop = &preparation->stack[preparation->stackCount]; + + machine->firstHeap = &preparation->heap[0]; + machine->freeHeap = &preparation->heap[preparation->heapCount - 1]; + machine->aliasCount = (txID)preparation->aliasCount; + + machine->onBreak = debugBreak; + + // memory map the archive using the first argument on the command line + if (archivePath) { + memArchive = loadArchive(archivePath); + } + + // map the symbols for the mod ("archive") + if (memArchive) { + archive = fxMapArchive(preparation, memArchive, memArchive, 4 * 1024, fxArchiveRead, fxArchiveWrite); + if (!archive) { + fprintf(stderr, "Failed to map the archive; continuing with no archive\n"); + } + } + + // instantiate the VM + machine = fxPrepareMachine(NULL, preparation, "machine", NULL, archive); + if (!machine) { + fprintf(stderr, "Failed to instantiate the VM\n"); + return 1; + } + + + // set up the stack context for XS + xsBeginHost(machine); + { + xsVars(1); + +#ifdef mxInstrument + // send the instrumentation headers, only if the debugger is connected + if (fxIsConnected(the)) + fxDescribeInstrumentation(machine, 0, NULL, NULL); + + // send the initial instrumentation data, only if the debugger is connected + if (fxIsConnected(the)) + fxSampleInstrumentation(the, 0, NULL); +#endif + { + // attempt to locate the "main" export from the host, and call it's function to start it + xsTry { + xsVar(0) = xsAwaitImport("main", XS_IMPORT_DEFAULT); + if (xsTest(xsVar(0))) { + if (xsIsInstanceOf(xsVar(0), xsFunctionPrototype)) { + xsCallFunction0(xsVar(0), xsGlobal); + } + } + } + xsCatch { + xsStringValue message = xsToString(xsException); + fprintf(stderr, "Uncaught error from VM: %s\n", message); + error = 1; + } + } + } + xsEndHost(the); + return error; +} + +/* + Terminates a running XS machine +*/ +void endMachine() { + xsDeleteMachine(machine); +} + +/* + Updates instrumentation (debugging statistics) for a running XS machine +*/ +void instrumentMachine() { +#ifdef mxDebug + xsBeginHost(machine); + { + // is the debugger connected? If not, skip to avoid console output + if (fxIsConnected(the)) + fxSampleInstrumentation(the, 0, NULL); + } + xsEndHost(the); +#endif +} + +/* + End point for XS to terminate execution +*/ +void fxAbort(xsMachine* the, int status) { + if (status == xsNotEnoughMemoryExit) + fprintf(stderr, "Abort: not enough memory\n"); + else if (status == xsStackOverflowExit) + fprintf(stderr, "Abort: stack overflow\n"); + else if (status == xsDeadStripExit) + fprintf(stderr, "Abort: dead strip\n"); + else if (status == xsUnhandledExceptionExit) + fprintf(stderr, "Abort: unhandled exception\n"); + else if (status != 0) + fprintf(stderr, "Abort: Error code %d\n", status); + exit(status); +} diff --git a/contributed/cli/x-cli-mac/machine.h b/contributed/cli/x-cli-mac/machine.h new file mode 100644 index 0000000000..ccfc881aa6 --- /dev/null +++ b/contributed/cli/x-cli-mac/machine.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 Chris Midgley + * + * This file is part of the Moddable SDK Tools. + * + * The Moddable SDK Tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Moddable SDK Tools. If not, see . + * + */ + +int startMachine(char *archivePath); +void endMachine(); +void instrumentMachine(); + diff --git a/contributed/cli/x-cli-mac/main.c b/contributed/cli/x-cli-mac/main.c new file mode 100644 index 0000000000..154644df2a --- /dev/null +++ b/contributed/cli/x-cli-mac/main.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2020 Chris Midgley + * + * This file is part of the Moddable SDK Tools. + * + * The Moddable SDK Tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Moddable SDK Tools. If not, see . + * + */ + +/* + This file implements a x-cli-mac platform for Moddable that supports an event loop and dynamically loaded + archives (mods). It implements the C main function, sets up XS machine and starts a Mac CFRunLoop message pump. + Upon a close message (which is intercepted and sent upon ^C) it cleanly shuts down the XS machine. It also + maintains the instrumentation updates, using a timer, on a once/second interval. +*/ + +#include "xsAll.h" +#include +#include +#include +#include +#include "machine.h" +#include "sysinfoapi.h" + +unsigned int messagePumpThreadId = 0; // thread ID of the thread running the windows message pump +#ifdef mxInstrument +#define WM_APP_INSTRUMENTATION (WM_APP + 1) // ID of our private instrumentation message + +static VOID CALLBACK sendInstrumentationMessage(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { + PostThreadMessage(messagePumpThreadId, WM_APP_INSTRUMENTATION, 0, 0); +} +#endif + + +/* + Message pump that manages the XS virtual machine. The machine is started up, then the Windows message + pump is executed allow for modules such as Timer to be used. Also maintains instrumentation to xsbug once + per second, triggered by the WM_APP_INSTRUMENTATION message from a timer. Shuts down the VM when a WM_CLOSE + message is received, and signals completion using the terminateEvent event. +*/ +void messagePump(char *pathToMod) +{ + MSG msg; + + // save away our thread ID - this is done so that the ^C interception can send us a WM_CLOSE message + messagePumpThreadId = GetCurrentThreadId(); + + // start up our VM + int error = startMachine(pathToMod); + + // set up a timer for the instrumentation +#ifdef mxInstrument + SetTimer(NULL, 1, 1000, sendInstrumentationMessage); +#endif + + // process the windows message loop until terminated + while( GetMessage(&msg, NULL, 0, 0) > 0 ) { +#ifdef mxInstrument + if (msg.message == WM_APP_INSTRUMENTATION) { + // make sure we don't issue instrumentation more often than once/second - if the host gets busy, a + // bunch of messages can be queued up, and this drops the extra ones on the floor + static DWORD instrumentTime = 0; + DWORD currentTime = GetTickCount(); + + if (instrumentTime < currentTime) { + instrumentTime = currentTime + 1000; + instrumentMachine(); + } + + continue; + } +#endif + + // do we need to shut down? + if (msg.message == WM_CLOSE) + break; + + // go ahead and let the message get dispatched + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // done - end our XS machine + endMachine(); +} + +/* + Handler for intercepting the ctrl-C shutdown of the process, and sends the WM_CLOSE message so the message pump can + initiate a shutdown +*/ +BOOL WINAPI ctrlHandler(_In_ DWORD dwCtrlType) { + switch (dwCtrlType) + { + case CTRL_C_EVENT: + PostThreadMessage(messagePumpThreadId, WM_CLOSE, 0, 0); + + return TRUE; + default: + // Pass signal on to the next handler + return FALSE; + } +} + + +/* + main - accepts a single optional command line argument that is the path to a mod to load + + Sets a ^C handler (for clearn shutdown) and starts up the VM and message pump +*/ +int main(int argc, char* argv[]) { + + // take control over ^C handling + SetConsoleCtrlHandler(ctrlHandler, TRUE); + + // start up the XS VM and run the message pump + messagePump((argc > 1) ? argv[1] : NULL); + + return 0; +} From e95ba18cd9b7c886475f8478f8aa29175f85d21b Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 26 Dec 2020 11:19:31 -0400 Subject: [PATCH 06/32] Removed unnecessary machine config --- contributed/cli/x-cli-win/machine.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/contributed/cli/x-cli-win/machine.c b/contributed/cli/x-cli-win/machine.c index 368e8bebf6..1f3bf166bc 100644 --- a/contributed/cli/x-cli-win/machine.c +++ b/contributed/cli/x-cli-win/machine.c @@ -106,27 +106,6 @@ int startMachine(char *archivePath) { void *memArchive = NULL; // memory mapped instance of the mod (archive) void *archive = NULL; // XS symbol-mapped archive - // set up the XS VM - c_memset(machine, 0, sizeof(txMachine)); - machine->preparation = preparation; - machine->keyArray = preparation->keys; - machine->keyCount = (txID)preparation->keyCount + (txID)preparation->creation.keyCount; - machine->keyIndex = (txID)preparation->keyCount; - machine->nameModulo = preparation->nameModulo; - machine->nameTable = preparation->names; - machine->symbolModulo = preparation->symbolModulo; - machine->symbolTable = preparation->symbols; - - machine->stack = &preparation->stack[0]; - machine->stackBottom = &preparation->stack[0]; - machine->stackTop = &preparation->stack[preparation->stackCount]; - - machine->firstHeap = &preparation->heap[0]; - machine->freeHeap = &preparation->heap[preparation->heapCount - 1]; - machine->aliasCount = (txID)preparation->aliasCount; - - machine->onBreak = debugBreak; - // memory map the archive using the first argument on the command line if (archivePath) { memArchive = loadArchive(archivePath); @@ -147,6 +126,8 @@ int startMachine(char *archivePath) { return 1; } + // set up to call our instrumentation update routing when we jump into the debugger + machine->onBreak = debugBreak; // set up the stack context for XS xsBeginHost(machine); From 9c943a0959c2d2cf0a4d92b527f0239b1a76877b Mon Sep 17 00:00:00 2001 From: Chris Midgley Date: Sat, 26 Dec 2020 11:47:59 -0400 Subject: [PATCH 07/32] Support for x-cli-mac --- contributed/cli/x-cli-mac/machine.c | 66 ++++++---------------- contributed/cli/x-cli-mac/main.c | 86 ++++++++--------------------- tools/mcconfig/make.x-cli-mac.mk | 19 +++++-- tools/mcrun/make.x-cli-mac.mk | 50 +++++++++++++++++ 4 files changed, 107 insertions(+), 114 deletions(-) create mode 100644 tools/mcrun/make.x-cli-mac.mk diff --git a/contributed/cli/x-cli-mac/machine.c b/contributed/cli/x-cli-mac/machine.c index 368e8bebf6..24654701d3 100644 --- a/contributed/cli/x-cli-mac/machine.c +++ b/contributed/cli/x-cli-mac/machine.c @@ -25,9 +25,8 @@ #include "xsAll.h" #include "mc.xs.h" +#include -HANDLE archiveFile = INVALID_HANDLE_VALUE; -HANDLE archiveMapping = INVALID_HANDLE_VALUE; static txMachine root; txMachine* machine = &root; @@ -49,36 +48,26 @@ xsBooleanValue fxArchiveWrite(void* dst, size_t offset, void* buffer, size_t siz } /* - Windows specific implementation to map an archive (mod) into memory. Accepts the path to the + Mac specific implementation to map an archive (mod) into memory. Accepts the path to the archive, and returns either a pointer to the memory mapped image, or NULL if there was a failure during the loading of the file. */ void *loadArchive(char *archivePath) { - if (archivePath[0]) { - DWORD size; - archiveFile = CreateFile(archivePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (archiveFile == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed to open archive %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - size = GetFileSize(archiveFile, &size); - if (size == INVALID_FILE_SIZE) { - fprintf(stderr, "Failed to get file size for %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - archiveMapping = CreateFileMapping(archiveFile, NULL, PAGE_READWRITE, 0, (SIZE_T)size, NULL); - if (archiveMapping == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed to create file mapping for %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - void *memArchive = MapViewOfFile(archiveMapping, FILE_MAP_WRITE, 0, 0, (SIZE_T)size); - if (memArchive == NULL) { - fprintf(stderr, "Failed to map view of file for %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - return memArchive; + struct stat statbuf; + int archiveFile; + + archiveFile = open(archivePath, O_RDWR); + if (archiveFile < 0) { + fprintf(stderr, "Filed to load archive %s (error %s)\n", archivePath, strerror(errno)); + return NULL; } - return NULL; + fstat(archiveFile, &statbuf); + void *archiveMapped = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, archiveFile, 0); + if (archiveMapped == MAP_FAILED) { + fprintf(stderr, "Filed to map archive %s (error %s)\n", archivePath, strerror(errno)); + return NULL; + } + return archiveMapped; } /* @@ -106,27 +95,6 @@ int startMachine(char *archivePath) { void *memArchive = NULL; // memory mapped instance of the mod (archive) void *archive = NULL; // XS symbol-mapped archive - // set up the XS VM - c_memset(machine, 0, sizeof(txMachine)); - machine->preparation = preparation; - machine->keyArray = preparation->keys; - machine->keyCount = (txID)preparation->keyCount + (txID)preparation->creation.keyCount; - machine->keyIndex = (txID)preparation->keyCount; - machine->nameModulo = preparation->nameModulo; - machine->nameTable = preparation->names; - machine->symbolModulo = preparation->symbolModulo; - machine->symbolTable = preparation->symbols; - - machine->stack = &preparation->stack[0]; - machine->stackBottom = &preparation->stack[0]; - machine->stackTop = &preparation->stack[preparation->stackCount]; - - machine->firstHeap = &preparation->heap[0]; - machine->freeHeap = &preparation->heap[preparation->heapCount - 1]; - machine->aliasCount = (txID)preparation->aliasCount; - - machine->onBreak = debugBreak; - // memory map the archive using the first argument on the command line if (archivePath) { memArchive = loadArchive(archivePath); @@ -147,6 +115,8 @@ int startMachine(char *archivePath) { return 1; } + // instruct the machine to call us prior to entering the debugger, so we can update instrumentation + machine->onBreak = debugBreak; // set up the stack context for XS xsBeginHost(machine); diff --git a/contributed/cli/x-cli-mac/main.c b/contributed/cli/x-cli-mac/main.c index 154644df2a..bae09f425f 100644 --- a/contributed/cli/x-cli-mac/main.c +++ b/contributed/cli/x-cli-mac/main.c @@ -20,96 +20,58 @@ /* This file implements a x-cli-mac platform for Moddable that supports an event loop and dynamically loaded - archives (mods). It implements the C main function, sets up XS machine and starts a Mac CFRunLoop message pump. + archives (mods). It implements the C main function, sets up XS machine and starts a Mac CFRunLoop message loop. Upon a close message (which is intercepted and sent upon ^C) it cleanly shuts down the XS machine. It also maintains the instrumentation updates, using a timer, on a once/second interval. */ #include "xsAll.h" -#include #include #include #include #include "machine.h" -#include "sysinfoapi.h" +#include -unsigned int messagePumpThreadId = 0; // thread ID of the thread running the windows message pump #ifdef mxInstrument -#define WM_APP_INSTRUMENTATION (WM_APP + 1) // ID of our private instrumentation message - -static VOID CALLBACK sendInstrumentationMessage(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - PostThreadMessage(messagePumpThreadId, WM_APP_INSTRUMENTATION, 0, 0); +/* + Called from a once/second timer (see runMessageLoop) and is used to trigger instrumentation for debugging +*/ +static void sendInstrumentation(CFRunLoopTimerRef cfTimer, void *info) { + instrumentMachine(); } #endif /* - Message pump that manages the XS virtual machine. The machine is started up, then the Windows message - pump is executed allow for modules such as Timer to be used. Also maintains instrumentation to xsbug once - per second, triggered by the WM_APP_INSTRUMENTATION message from a timer. Shuts down the VM when a WM_CLOSE - message is received, and signals completion using the terminateEvent event. + Message loop that manages the XS virtual machine. The machine is started up, a timer is created to update + instrumentation every second, and then the Mac message loop is executed. */ -void messagePump(char *pathToMod) +int runMessageLoop(char *pathToMod) { - MSG msg; - - // save away our thread ID - this is done so that the ^C interception can send us a WM_CLOSE message - messagePumpThreadId = GetCurrentThreadId(); - // start up our VM int error = startMachine(pathToMod); // set up a timer for the instrumentation #ifdef mxInstrument - SetTimer(NULL, 1, 1000, sendInstrumentationMessage); + CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 1, + 1, 0, 0, sendInstrumentation, NULL); + CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes); #endif - // process the windows message loop until terminated - while( GetMessage(&msg, NULL, 0, 0) > 0 ) { -#ifdef mxInstrument - if (msg.message == WM_APP_INSTRUMENTATION) { - // make sure we don't issue instrumentation more often than once/second - if the host gets busy, a - // bunch of messages can be queued up, and this drops the extra ones on the floor - static DWORD instrumentTime = 0; - DWORD currentTime = GetTickCount(); - - if (instrumentTime < currentTime) { - instrumentTime = currentTime + 1000; - instrumentMachine(); - } - - continue; - } -#endif - - // do we need to shut down? - if (msg.message == WM_CLOSE) - break; - - // go ahead and let the message get dispatched - TranslateMessage(&msg); - DispatchMessage(&msg); - } + // process the message loop until terminated + CFRunLoopRun(); // done - end our XS machine endMachine(); + + return error; } /* - Handler for intercepting the ctrl-C shutdown of the process, and sends the WM_CLOSE message so the message pump can - initiate a shutdown + Handler for intercepting the ctrl-C shutdown of the process, and instructs the CFRunLoop to shutdown */ -BOOL WINAPI ctrlHandler(_In_ DWORD dwCtrlType) { - switch (dwCtrlType) - { - case CTRL_C_EVENT: - PostThreadMessage(messagePumpThreadId, WM_CLOSE, 0, 0); - - return TRUE; - default: - // Pass signal on to the next handler - return FALSE; - } +void ctrlHandler(int sig) { + CFRunLoopStop(CFRunLoopGetCurrent()); } @@ -121,10 +83,10 @@ BOOL WINAPI ctrlHandler(_In_ DWORD dwCtrlType) { int main(int argc, char* argv[]) { // take control over ^C handling - SetConsoleCtrlHandler(ctrlHandler, TRUE); + signal(SIGINT, &ctrlHandler); - // start up the XS VM and run the message pump - messagePump((argc > 1) ? argv[1] : NULL); + // start up the XS VM and run the message loop + int error = runMessageLoop((argc > 1) ? argv[1] : NULL); - return 0; + return error; } diff --git a/tools/mcconfig/make.x-cli-mac.mk b/tools/mcconfig/make.x-cli-mac.mk index e47e33eb4e..3c482be282 100644 --- a/tools/mcconfig/make.x-cli-mac.mk +++ b/tools/mcconfig/make.x-cli-mac.mk @@ -27,6 +27,9 @@ else endif endif +MCREZ = $(BUILD_DIR)/bin/mac/release/mcrez + + XS_DIRECTORIES = \ $(XS_DIR)/includes \ $(XS_DIR)/platforms \ @@ -114,7 +117,7 @@ else endif C_FLAGS = $(XS_C_FLAGS) -LIBRARIES = -framework CoreFoundation -lcurl -lpng16 +LIBRARIES = -framework CoreFoundation # LINK_FLAGS = -arch i386 LINK_FLAGS = @@ -143,9 +146,9 @@ $(BIN_DIR)/Info.plist: $(MAIN_DIR)/mac/main.plist cp -rf $< $@ echo APPLTINY > $(BIN_DIR)/PkgInfo -$(BIN_DIR)/$(NAME): $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(OBJECTS) - @echo "# cc" $(@F) - $(CC) $(LINK_FLAGS) $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(OBJECTS) $(LIBRARIES) -o $@ +$(BIN_DIR)/$(NAME): $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.c.o $(OBJECTS) + @echo "# cc" $(@F) "($@)" + $(CC) $(LINK_FLAGS) $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.c.o $(OBJECTS) $(LIBRARIES) -o $@ $(XS_OBJECTS) : $(XS_HEADERS) $(LIB_DIR)/%.c.o: %.c @@ -159,6 +162,14 @@ $(TMP_DIR)/mc.xs.c.o: $(TMP_DIR)/mc.xs.c $(HEADERS) $(TMP_DIR)/mc.xs.c: $(MODULES) $(MANIFEST) @echo "# xsl modules" $(XSL) -b $(MODULES_DIR) -o $(TMP_DIR) $(PRELOADS) $(CREATION) $(MODULES) + +$(TMP_DIR)/mc.resources.c.o: $(TMP_DIR)/mc.resources.c $(HEADERS) + @echo "# cc" $(. +# + +ifeq ($(DEBUG),1) + START_XSBUG = open -a $(BUILD_DIR)/bin/mac/release/xsbug.app -g + KILL_SERIAL2XSBUG = $(shell pkill serial2xsbug) +else + START_XSBUG = + KILL_SERIAL2XSBUG = +endif + +BUILDCLUT = $(BUILD_DIR)/bin/mac/release/buildclut +COMPRESSBMF = $(BUILD_DIR)/bin/mac/release/compressbmf +IMAGE2CS = $(BUILD_DIR)/bin/mac/release/image2cs +MCLOCAL = $(BUILD_DIR)/bin/mac/release/mclocal +MCREZ = $(BUILD_DIR)/bin/mac/release/mcrez +PNG2BMP = $(BUILD_DIR)/bin/mac/release/png2bmp +RLE4ENCODE = $(BUILD_DIR)/bin/mac/release/rle4encode +WAV2MAUD = $(BUILD_DIR)/bin/mac/release/wav2maud +XSC = $(MODDABLE)/build/bin/mac/release/xsc +XSL = $(MODDABLE)/build/bin/mac/release/xsl + +.PHONY: all + +all: $(BIN_DIR)/mc.xsa + +$(BIN_DIR)/mc.xsa: $(DATA) $(MODULES) $(RESOURCES) + @echo "# xsl mc.xsa ($@)" + $(XSL) -a -b $(MODULES_DIR) -n $(DOT_SIGNATURE) -o $(BIN_DIR) $(DATA) $(MODULES) $(RESOURCES) + +ifneq ($(VERBOSE),1) +MAKEFLAGS += --silent +endif + From 671b9a14220068d1826518c04314876a7e23e512 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 26 Dec 2020 12:12:30 -0400 Subject: [PATCH 08/32] Start of x-cli-lin support --- tools/mcconfig/make.x-cli-lin.mk | 208 +++++++++++++++++++++++++++++++ tools/mcrun/make.x-cli-lin.mk | 43 +++++++ 2 files changed, 251 insertions(+) create mode 100644 tools/mcconfig/make.x-cli-lin.mk create mode 100644 tools/mcrun/make.x-cli-lin.mk diff --git a/tools/mcconfig/make.x-cli-lin.mk b/tools/mcconfig/make.x-cli-lin.mk new file mode 100644 index 0000000000..76a3b328df --- /dev/null +++ b/tools/mcconfig/make.x-cli-lin.mk @@ -0,0 +1,208 @@ +# +# Copyright (c) 2016-2020 Moddable Tech, Inc. +# +# This file is part of the Moddable SDK Tools. +# +# The Moddable SDK Tools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# The Moddable SDK Tools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Moddable SDK Tools. If not, see . +# + +ifeq ($(DEBUG),1) + LIB_DIR = $(BUILD_DIR)/tmp/lin/debug/lib +else + ifeq ($(INSTRUMENT),1) + LIB_DIR = $(BUILD_DIR)/tmp/lin/instrument/lib + else + LIB_DIR = $(BUILD_DIR)/tmp/lin/release/lib + endif +endif + +XS_DIRECTORIES = \ + $(XS_DIR)/includes \ + $(XS_DIR)/platforms \ + $(XS_DIR)/sources + +XS_HEADERS = \ + $(XS_DIR)/platforms/lin_xs.h \ + $(XS_DIR)/platforms/xsPlatform.h \ + $(XS_DIR)/includes/xs.h \ + $(XS_DIR)/includes/xsmc.h \ + $(XS_DIR)/sources/xsCommon.h \ + $(XS_DIR)/sources/xsAll.h \ + $(XS_DIR)/sources/xsScript.h + +XS_OBJECTS = \ + $(LIB_DIR)/lin_xs.c.o \ + $(LIB_DIR)/xsAll.c.o \ + $(LIB_DIR)/xsAPI.c.o \ + $(LIB_DIR)/xsArguments.c.o \ + $(LIB_DIR)/xsArray.c.o \ + $(LIB_DIR)/xsAtomics.c.o \ + $(LIB_DIR)/xsBigInt.c.o \ + $(LIB_DIR)/xsBoolean.c.o \ + $(LIB_DIR)/xsCode.c.o \ + $(LIB_DIR)/xsCommon.c.o \ + $(LIB_DIR)/xsDataView.c.o \ + $(LIB_DIR)/xsDate.c.o \ + $(LIB_DIR)/xsDebug.c.o \ + $(LIB_DIR)/xsError.c.o \ + $(LIB_DIR)/xsFunction.c.o \ + $(LIB_DIR)/xsGenerator.c.o \ + $(LIB_DIR)/xsGlobal.c.o \ + $(LIB_DIR)/xsJSON.c.o \ + $(LIB_DIR)/xsLexical.c.o \ + $(LIB_DIR)/xsMapSet.c.o \ + $(LIB_DIR)/xsMarshall.c.o \ + $(LIB_DIR)/xsMath.c.o \ + $(LIB_DIR)/xsMemory.c.o \ + $(LIB_DIR)/xsModule.c.o \ + $(LIB_DIR)/xsNumber.c.o \ + $(LIB_DIR)/xsObject.c.o \ + $(LIB_DIR)/xsPlatforms.c.o \ + $(LIB_DIR)/xsProfile.c.o \ + $(LIB_DIR)/xsPromise.c.o \ + $(LIB_DIR)/xsProperty.c.o \ + $(LIB_DIR)/xsProxy.c.o \ + $(LIB_DIR)/xsRegExp.c.o \ + $(LIB_DIR)/xsRun.c.o \ + $(LIB_DIR)/xsScope.c.o \ + $(LIB_DIR)/xsScript.c.o \ + $(LIB_DIR)/xsSourceMap.c.o \ + $(LIB_DIR)/xsString.c.o \ + $(LIB_DIR)/xsSymbol.c.o \ + $(LIB_DIR)/xsSyntaxical.c.o \ + $(LIB_DIR)/xsTree.c.o \ + $(LIB_DIR)/xsType.c.o \ + $(LIB_DIR)/xsdtoa.c.o \ + $(LIB_DIR)/xsmc.c.o \ + $(LIB_DIR)/xsre.c.o + +HEADERS += $(XS_HEADERS) + +PKGCONFIG = $(shell which pkg-config) +GLIB_COMPILE_RESOURCES = $(shell $(PKGCONFIG) --variable=glib_compile_resources gio-2.0) + +C_DEFINES = \ + -DXS_ARCHIVE=1 \ + -DINCLUDE_XSPLATFORM=1 \ + -DXSPLATFORM=\"lin_xs.h\" \ + -DmxRun=1 \ + -DmxParse=1 \ + -DmxNoFunctionLength=1 \ + -DmxNoFunctionName=1 \ + -DmxHostFunctionPrimitive=1 \ + -DmxFewGlobalsTable=1 +C_DEFINES += \ + -Wno-misleading-indentation \ + -Wno-implicit-fallthrough +ifeq ($(INSTRUMENT),1) + C_DEFINES += -DMODINSTRUMENTATION=1 -DmxInstrument=1 +endif +C_INCLUDES += $(DIRECTORIES) +C_INCLUDES += $(foreach dir,$(XS_DIRECTORIES) $(TMP_DIR),-I$(dir)) +C_FLAGS = -fPIC -c $(shell $(PKGCONFIG) --cflags freetype2 gtk+-3.0) +ifeq ($(DEBUG),) + C_FLAGS += -D_RELEASE=1 -O3 +else + C_FLAGS += -D_DEBUG=1 -DmxDebug=1 -g -O0 -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter +# C_FLAGS += -DMC_MEMORY_DEBUG=1 +endif + +LINK_LIBRARIES = -lm -lc $(shell $(PKGCONFIG) --libs freetype2 gtk+-3.0) -ldl -latomic + +LINK_OPTIONS = -fPIC + +ifeq ($(DEBUG),1) +MCLOCAL = $(BUILD_DIR)/bin/mac/debug/mclocal +MCREZ = $(BUILD_DIR)/bin/lin/debug/mcrez +XSC = $(BUILD_DIR)/bin/lin/debug/xsc +XSID = $(BUILD_DIR)/bin/lin/debug/xsid +XSL = $(BUILD_DIR)/bin/lin/debug/xsl +else +MCLOCAL = $(BUILD_DIR)/bin/mac/release/mclocal +MCREZ = $(BUILD_DIR)/bin/lin/release/mcrez +XSC = $(BUILD_DIR)/bin/lin/release/xsc +XSID = $(BUILD_DIR)/bin/lin/release/xsid +XSL = $(BUILD_DIR)/bin/lin/release/xsl +endif + +VPATH += $(XS_DIRECTORIES) + +.PHONY: all + +all: build + +build: $(LIB_DIR) $(BIN_DIR)/$(NAME) + +$(LIB_DIR): + mkdir -p $(LIB_DIR) + +$(BIN_DIR)/$(NAME): $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.o $(OBJECTS) + @echo "# ld " $(/dev/null + -rm -rf $(TMP_DIR) 2>/dev/null + +$(XS_OBJECTS) : $(XS_HEADERS) +$(LIB_DIR)/%.c.o: %.c + @echo "# cc" $(. +# + +BUILDCLUT = $(BUILD_DIR)/bin/lin/release/buildclut +COMPRESSBMF = $(BUILD_DIR)/bin/lin/release/compressbmf +IMAGE2CS = $(BUILD_DIR)/bin/lin/release/image2cs +MCLOCAL = $(BUILD_DIR)/bin/lin/release/mclocal +MCREZ = $(BUILD_DIR)/bin/lin/release/mcrez +PNG2BMP = $(BUILD_DIR)/bin/lin/release/png2bmp +RLE4ENCODE = $(BUILD_DIR)/bin/lin/release/rle4encode +WAV2MAUD = $(BUILD_DIR)/bin/lin/release/wav2maud +XSC = $(MODDABLE)/build/bin/lin/release/xsc +XSL = $(MODDABLE)/build/bin/lin/release/xsl + +.PHONY: all + +all: $(BIN_DIR)/mc.xsa + $(shell nohup $(SIMULATOR) $(BIN_DIR)/mc.xsa > /dev/null 2>&1 &) + +$(BIN_DIR)/mc.xsa: $(DATA) $(MODULES) $(RESOURCES) + @echo "# xsl mc.xsa ($(BIN_DIR)/mc.xsa)" + $(XSL) -a -b $(MODULES_DIR) -n $(DOT_SIGNATURE) -o $(BIN_DIR) $(DATA) $(MODULES) $(RESOURCES) + +ifneq ($(VERBOSE),1) +MAKEFLAGS += --silent +endif + From 037ebc0773851d2bd1bf3ca690d4f308b2546b3a Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 26 Dec 2020 12:12:45 -0400 Subject: [PATCH 09/32] Fake module for preferences for linux --- modules/files/preference/lin/modPreference.c | 63 ++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 modules/files/preference/lin/modPreference.c diff --git a/modules/files/preference/lin/modPreference.c b/modules/files/preference/lin/modPreference.c new file mode 100644 index 0000000000..ec2b918d49 --- /dev/null +++ b/modules/files/preference/lin/modPreference.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016-2018 Moddable Tech, Inc. + * + * This file is part of the Moddable SDK Runtime. + * + * The Moddable SDK Runtime is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Runtime is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the Moddable SDK Runtime. If not, see . + * + */ + +#include "xsmc.h" +#include "xsHost.h" +#include "mc.xs.h" // for xsID_ values + +#define kPreferencesMagic 0x81213141 + +enum { + kPrefsTypeBoolean = 1, + kPrefsTypeInteger = 2, + kPrefsTypeString = 3, + kPrefsTypeBuffer = 4, +}; + +#define kBufferSize (64) + +static void resetPrefs(void); +static uint8_t findPrefsBlock(uint32_t *offset); +static uint8_t findPrefOffset(const char *domain, const char *key, uint32_t *entryOffset, uint32_t *valueOffset, uint32_t *entrySize, uint8_t *buffer); +static int getPrefSize(const uint8_t *pref); +static uint8_t erasePref(const char *domain, const char *key, uint8_t *buffer); +static uint8_t setPref(xsMachine *the, char *domain, char *name, uint8_t type, uint8_t *value, uint16_t byteCount); + +void xs_preference_set(xsMachine *the) +{ + xsUnknownError("can't save prefs"); +} + +void xs_preference_get(xsMachine *the) +{ +} + +void xs_preference_delete(xsMachine *the) +{ +} + +void xs_preference_keys(xsMachine *the) +{ +} + +void xs_preference_reset(xsMachine *the) +{ +} + From 4b426a973cfaf8d2e770dc889e59c5e90cd1a040 Mon Sep 17 00:00:00 2001 From: Chris Midgley Date: Sun, 27 Dec 2020 06:36:39 -0800 Subject: [PATCH 10/32] Basic support for x-cli-lin --- contributed/cli/x-cli-lin/machine.c | 67 +++++---------- contributed/cli/x-cli-lin/main.c | 123 +++++++++++----------------- tools/mcconfig/make.x-cli-lin.mk | 41 ++++------ 3 files changed, 82 insertions(+), 149 deletions(-) diff --git a/contributed/cli/x-cli-lin/machine.c b/contributed/cli/x-cli-lin/machine.c index 368e8bebf6..71ff35dd5d 100644 --- a/contributed/cli/x-cli-lin/machine.c +++ b/contributed/cli/x-cli-lin/machine.c @@ -25,9 +25,9 @@ #include "xsAll.h" #include "mc.xs.h" +#include +#include -HANDLE archiveFile = INVALID_HANDLE_VALUE; -HANDLE archiveMapping = INVALID_HANDLE_VALUE; static txMachine root; txMachine* machine = &root; @@ -49,36 +49,26 @@ xsBooleanValue fxArchiveWrite(void* dst, size_t offset, void* buffer, size_t siz } /* - Windows specific implementation to map an archive (mod) into memory. Accepts the path to the + Mac specific implementation to map an archive (mod) into memory. Accepts the path to the archive, and returns either a pointer to the memory mapped image, or NULL if there was a failure during the loading of the file. */ void *loadArchive(char *archivePath) { - if (archivePath[0]) { - DWORD size; - archiveFile = CreateFile(archivePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (archiveFile == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed to open archive %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - size = GetFileSize(archiveFile, &size); - if (size == INVALID_FILE_SIZE) { - fprintf(stderr, "Failed to get file size for %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - archiveMapping = CreateFileMapping(archiveFile, NULL, PAGE_READWRITE, 0, (SIZE_T)size, NULL); - if (archiveMapping == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed to create file mapping for %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - void *memArchive = MapViewOfFile(archiveMapping, FILE_MAP_WRITE, 0, 0, (SIZE_T)size); - if (memArchive == NULL) { - fprintf(stderr, "Failed to map view of file for %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - return memArchive; + struct stat statbuf; + int archiveFile; + + archiveFile = open(archivePath, O_RDWR); + if (archiveFile < 0) { + fprintf(stderr, "Filed to load archive %s (error %s)\n", archivePath, strerror(errno)); + return NULL; } - return NULL; + fstat(archiveFile, &statbuf); + void *archiveMapped = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, archiveFile, 0); + if (archiveMapped == MAP_FAILED) { + fprintf(stderr, "Filed to map archive %s (error %s)\n", archivePath, strerror(errno)); + return NULL; + } + return archiveMapped; } /* @@ -106,27 +96,6 @@ int startMachine(char *archivePath) { void *memArchive = NULL; // memory mapped instance of the mod (archive) void *archive = NULL; // XS symbol-mapped archive - // set up the XS VM - c_memset(machine, 0, sizeof(txMachine)); - machine->preparation = preparation; - machine->keyArray = preparation->keys; - machine->keyCount = (txID)preparation->keyCount + (txID)preparation->creation.keyCount; - machine->keyIndex = (txID)preparation->keyCount; - machine->nameModulo = preparation->nameModulo; - machine->nameTable = preparation->names; - machine->symbolModulo = preparation->symbolModulo; - machine->symbolTable = preparation->symbols; - - machine->stack = &preparation->stack[0]; - machine->stackBottom = &preparation->stack[0]; - machine->stackTop = &preparation->stack[preparation->stackCount]; - - machine->firstHeap = &preparation->heap[0]; - machine->freeHeap = &preparation->heap[preparation->heapCount - 1]; - machine->aliasCount = (txID)preparation->aliasCount; - - machine->onBreak = debugBreak; - // memory map the archive using the first argument on the command line if (archivePath) { memArchive = loadArchive(archivePath); @@ -147,6 +116,8 @@ int startMachine(char *archivePath) { return 1; } + // instruct the machine to call us prior to entering the debugger, so we can update instrumentation + machine->onBreak = debugBreak; // set up the stack context for XS xsBeginHost(machine); diff --git a/contributed/cli/x-cli-lin/main.c b/contributed/cli/x-cli-lin/main.c index 2aae632057..f5e8cdc740 100644 --- a/contributed/cli/x-cli-lin/main.c +++ b/contributed/cli/x-cli-lin/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Chris Midgley + * Copyright (c) 2016-2017 Chris Midgley * * This file is part of the Moddable SDK Tools. * @@ -19,112 +19,87 @@ */ /* - This file implements a x-cli-win platform for Moddable that supports an event loop and dynamically loaded - archives (mods). It implements the C main function, sets up XS machine and starts a Windows message pump. - Upon a WM_CLOSE message (which is intercepted and sent upon ^C) it cleanly shuts down the XS machine. It also + This file implements a x-cli-lin platform for Moddable that supports an event loop and dynamically loaded + archives (mods). It implements the C main function, sets up XS machine and starts a Mac CFRunLoop message loop. + Upon a close message (which is intercepted and sent upon ^C) it cleanly shuts down the XS machine. It also maintains the instrumentation updates, using a timer, on a once/second interval. */ #include "xsAll.h" -#include #include #include #include #include "machine.h" -#include "sysinfoapi.h" +#include +#include -unsigned int messagePumpThreadId = 0; // thread ID of the thread running the windows message pump -#ifdef mxInstrument -#define WM_APP_INSTRUMENTATION (WM_APP + 1) // ID of our private instrumentation message +static GtkApplication *gxApplication = NULL; +static GtkWindow *gxWindow; +static GtkApplication *app; -static VOID CALLBACK sendInstrumentationMessage(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - PostThreadMessage(messagePumpThreadId, WM_APP_INSTRUMENTATION, 0, 0); +#ifdef mxInstrument +/* + Called from a once/second timer (see runMessageLoop) and is used to trigger instrumentation for debugging +*/ +gboolean sendInstrumentation(gpointer userData) { + instrumentMachine(); + return TRUE; } #endif -/* - Message pump that manages the XS virtual machine. The machine is started up, then the Windows message - pump is executed allow for modules such as Timer to be used. Also maintains instrumentation to xsbug once - per second, triggered by the WM_APP_INSTRUMENTATION message from a timer. Shuts down the VM when a WM_CLOSE - message is received, and signals completion using the terminateEvent event. -*/ -void messagePump(char *pathToMod) +void onApplicationActivate(GtkApplication *app, gpointer it) { - MSG msg; - - // save away our thread ID - this is done so that the ^C interception can send us a WM_CLOSE message - messagePumpThreadId = GetCurrentThreadId(); - // start up our VM - int error = startMachine(pathToMod); + startMachine(NULL); - // set up a timer for the instrumentation -#ifdef mxInstrument - SetTimer(NULL, 1, 1000, sendInstrumentationMessage); -#endif - - // process the windows message loop until terminated - while( GetMessage(&msg, NULL, 0, 0) > 0 ) { -#ifdef mxInstrument - if (msg.message == WM_APP_INSTRUMENTATION) { - // make sure we don't issue instrumentation more often than once/second - if the host gets busy, a - // bunch of messages can be queued up, and this drops the extra ones on the floor - static DWORD instrumentTime = 0; - DWORD currentTime = GetTickCount(); - - if (instrumentTime < currentTime) { - instrumentTime = currentTime + 1000; - instrumentMachine(); - } - - continue; - } -#endif - - // do we need to shut down? - if (msg.message == WM_CLOSE) - break; - - // go ahead and let the message get dispatched - TranslateMessage(&msg); - DispatchMessage(&msg); - } + // set up a timer for instrumentation updates once/second + g_timeout_add(1000, sendInstrumentation, NULL); +} +void onApplicationShutdown(GtkApplication *app, gpointer it) +{ // done - end our XS machine endMachine(); } +void onApplicationStartup(GtkApplication *app) +{ + // create a window to keep our application running, but don't show it (so we logically remain a console app) + gxWindow = (GtkWindow*)gtk_application_window_new(app); +} + /* - Handler for intercepting the ctrl-C shutdown of the process, and sends the WM_CLOSE message so the message pump can - initiate a shutdown + Handler for intercepting the ctrl-C shutdown of the process, and instructs the CFRunLoop to shutdown */ -BOOL WINAPI ctrlHandler(_In_ DWORD dwCtrlType) { - switch (dwCtrlType) - { - case CTRL_C_EVENT: - PostThreadMessage(messagePumpThreadId, WM_CLOSE, 0, 0); - - return TRUE; - default: - // Pass signal on to the next handler - return FALSE; - } +void ctrlHandler(int sig) { + g_application_quit(G_APPLICATION(app)); + fprintf(stderr, "\nShutting down\n"); } /* main - accepts a single optional command line argument that is the path to a mod to load - Sets a ^C handler (for clearn shutdown) and starts up the VM and message pump + Sets a ^C handler (for clearn shutdown) and starts up the GTK application + + Note: This depends on GTK, which also means X, as the Moddable 'lin' machine depends deeply on GTK. This means + that this "cli" application will not work on SSH or headless Linux without installing X and likely using + xvfb (x frame buffer). */ -int main(int argc, char* argv[]) { +int main(int argc, char** argv) +{ + int status; // take control over ^C handling - SetConsoleCtrlHandler(ctrlHandler, TRUE); + signal(SIGINT, &ctrlHandler); - // start up the XS VM and run the message pump - messagePump((argc > 1) ? argv[1] : NULL); + app = gxApplication = gtk_application_new("tech.moddable.cli", G_APPLICATION_HANDLES_OPEN); + g_signal_connect(app, "startup", G_CALLBACK(onApplicationStartup), NULL); + g_signal_connect(app, "activate", G_CALLBACK(onApplicationActivate), NULL); + g_signal_connect(app, "shutdown", G_CALLBACK(onApplicationShutdown), NULL); + status = g_application_run(G_APPLICATION(app), argc, argv); - return 0; + g_object_unref(app); + return status; } diff --git a/tools/mcconfig/make.x-cli-lin.mk b/tools/mcconfig/make.x-cli-lin.mk index 76a3b328df..0fa5d821e6 100644 --- a/tools/mcconfig/make.x-cli-lin.mk +++ b/tools/mcconfig/make.x-cli-lin.mk @@ -147,8 +147,8 @@ build: $(LIB_DIR) $(BIN_DIR)/$(NAME) $(LIB_DIR): mkdir -p $(LIB_DIR) -$(BIN_DIR)/$(NAME): $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.o $(OBJECTS) - @echo "# ld " $( Date: Sun, 27 Dec 2020 11:11:33 -0400 Subject: [PATCH 11/32] Refactored to clean up common code across lin,mac,win --- .../cli/{x-cli-mac/machine.c => cli.c} | 29 +-- .../cli/{x-cli-win/machine.h => cli.h} | 1 + contributed/cli/manifest.json | 30 +-- contributed/cli/x-cli-lin/machine.c | 194 ----------------- contributed/cli/x-cli-lin/machine.h | 24 --- contributed/cli/x-cli-lin/main.c | 57 ++++- contributed/cli/x-cli-mac/machine.h | 24 --- contributed/cli/x-cli-mac/main.c | 28 ++- contributed/cli/x-cli-win/machine.c | 204 ------------------ contributed/cli/x-cli-win/main.c | 40 +++- 10 files changed, 120 insertions(+), 511 deletions(-) rename contributed/cli/{x-cli-mac/machine.c => cli.c} (83%) rename contributed/cli/{x-cli-win/machine.h => cli.h} (95%) delete mode 100644 contributed/cli/x-cli-lin/machine.c delete mode 100644 contributed/cli/x-cli-lin/machine.h delete mode 100644 contributed/cli/x-cli-mac/machine.h delete mode 100644 contributed/cli/x-cli-win/machine.c diff --git a/contributed/cli/x-cli-mac/machine.c b/contributed/cli/cli.c similarity index 83% rename from contributed/cli/x-cli-mac/machine.c rename to contributed/cli/cli.c index 24654701d3..005d5f71bc 100644 --- a/contributed/cli/x-cli-mac/machine.c +++ b/contributed/cli/cli.c @@ -19,13 +19,13 @@ */ /* - This file implements services for the x-cli-win platform to start/stop the XS virtual machine, provide loading of - archives (mods), and handling of instrumentation updates. + This file implements common services across all platforms to implement the "x-cli-XXX" runtime for Moddable, + including support for starting/stopping the XS virtual machine, and providing loading of archives (mods). */ #include "xsAll.h" #include "mc.xs.h" -#include +#include "cli.h" static txMachine root; txMachine* machine = &root; @@ -47,28 +47,7 @@ xsBooleanValue fxArchiveWrite(void* dst, size_t offset, void* buffer, size_t siz return 1; } -/* - Mac specific implementation to map an archive (mod) into memory. Accepts the path to the - archive, and returns either a pointer to the memory mapped image, or NULL if there was a failure during the loading - of the file. -*/ -void *loadArchive(char *archivePath) { - struct stat statbuf; - int archiveFile; - - archiveFile = open(archivePath, O_RDWR); - if (archiveFile < 0) { - fprintf(stderr, "Filed to load archive %s (error %s)\n", archivePath, strerror(errno)); - return NULL; - } - fstat(archiveFile, &statbuf); - void *archiveMapped = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, archiveFile, 0); - if (archiveMapped == MAP_FAILED) { - fprintf(stderr, "Filed to map archive %s (error %s)\n", archivePath, strerror(errno)); - return NULL; - } - return archiveMapped; -} + /* Callback function when the debugger is executed (see machine->onBreak). Updates the instrumentation so diff --git a/contributed/cli/x-cli-win/machine.h b/contributed/cli/cli.h similarity index 95% rename from contributed/cli/x-cli-win/machine.h rename to contributed/cli/cli.h index ccfc881aa6..7ed2b1f796 100644 --- a/contributed/cli/x-cli-win/machine.h +++ b/contributed/cli/cli.h @@ -21,4 +21,5 @@ int startMachine(char *archivePath); void endMachine(); void instrumentMachine(); +void *loadArchive(char *archivePath); diff --git a/contributed/cli/manifest.json b/contributed/cli/manifest.json index 3290a4e3d6..892efdc021 100644 --- a/contributed/cli/manifest.json +++ b/contributed/cli/manifest.json @@ -1,28 +1,8 @@ { - "platforms": { - "x-cli-win": { - "modules": { - "*": [ - "./x-cli-win/main", - "./x-cli-win/machine" - ] - } - }, - "x-cli-mac": { - "modules": { - "*": [ - "./x-cli-mac/main", - "./x-cli-mac/machine" - ] - } - }, - "x-cli-lin": { - "modules": { - "*": [ - "./x-cli-lin/main", - "./x-cli-lin/machine" - ] - } - } + "modules": { + "*": [ + "./$(PLATFORM)/main", + "./cli" + ] } } \ No newline at end of file diff --git a/contributed/cli/x-cli-lin/machine.c b/contributed/cli/x-cli-lin/machine.c deleted file mode 100644 index 71ff35dd5d..0000000000 --- a/contributed/cli/x-cli-lin/machine.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2016-2020 Moddable Tech, Inc. and Chris Midgley - * - * This file is part of the Moddable SDK Runtime. - * - * The Moddable SDK Runtime is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Moddable SDK Runtime is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the Moddable SDK Runtime. If not, see . - * - */ - -/* - This file implements services for the x-cli-win platform to start/stop the XS virtual machine, provide loading of - archives (mods), and handling of instrumentation updates. -*/ - -#include "xsAll.h" -#include "mc.xs.h" -#include -#include - -static txMachine root; -txMachine* machine = &root; - - -/* - Service used by fxMapArchive to read a section of the archive (mod) from memory -*/ -xsBooleanValue fxArchiveRead(void* src, size_t offset, void* buffer, size_t size) { - c_memcpy(buffer, ((txU1*)src) + offset, size); - return 1; -} - -/* - Service used by fxMapArchive to write a section of the archive (mod) in memory -*/ -xsBooleanValue fxArchiveWrite(void* dst, size_t offset, void* buffer, size_t size) { - c_memcpy(((txU1*)dst) + offset, buffer, size); - return 1; -} - -/* - Mac specific implementation to map an archive (mod) into memory. Accepts the path to the - archive, and returns either a pointer to the memory mapped image, or NULL if there was a failure during the loading - of the file. -*/ -void *loadArchive(char *archivePath) { - struct stat statbuf; - int archiveFile; - - archiveFile = open(archivePath, O_RDWR); - if (archiveFile < 0) { - fprintf(stderr, "Filed to load archive %s (error %s)\n", archivePath, strerror(errno)); - return NULL; - } - fstat(archiveFile, &statbuf); - void *archiveMapped = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, archiveFile, 0); - if (archiveMapped == MAP_FAILED) { - fprintf(stderr, "Filed to map archive %s (error %s)\n", archivePath, strerror(errno)); - return NULL; - } - return archiveMapped; -} - -/* - Callback function when the debugger is executed (see machine->onBreak). Updates the instrumentation so - breakpoints have accurate instrumentation just prior to stopping. -*/ -void debugBreak(xsMachine* the, uint8_t stop) -{ -#ifdef mxInstrument - if (stop) { - // fxCollectGarbage(the); - // the->garbageCollectionCount -= 1; - fxSampleInstrumentation(the, 0, NULL); - } -#endif -} - -/* - Starts up an XS machine, including loading and mapping the archive (mod) and calling the exported - function "main". -*/ -int startMachine(char *archivePath) { - int error = 0; - txPreparation* preparation = xsPreparation(); - void *memArchive = NULL; // memory mapped instance of the mod (archive) - void *archive = NULL; // XS symbol-mapped archive - - // memory map the archive using the first argument on the command line - if (archivePath) { - memArchive = loadArchive(archivePath); - } - - // map the symbols for the mod ("archive") - if (memArchive) { - archive = fxMapArchive(preparation, memArchive, memArchive, 4 * 1024, fxArchiveRead, fxArchiveWrite); - if (!archive) { - fprintf(stderr, "Failed to map the archive; continuing with no archive\n"); - } - } - - // instantiate the VM - machine = fxPrepareMachine(NULL, preparation, "machine", NULL, archive); - if (!machine) { - fprintf(stderr, "Failed to instantiate the VM\n"); - return 1; - } - - // instruct the machine to call us prior to entering the debugger, so we can update instrumentation - machine->onBreak = debugBreak; - - // set up the stack context for XS - xsBeginHost(machine); - { - xsVars(1); - -#ifdef mxInstrument - // send the instrumentation headers, only if the debugger is connected - if (fxIsConnected(the)) - fxDescribeInstrumentation(machine, 0, NULL, NULL); - - // send the initial instrumentation data, only if the debugger is connected - if (fxIsConnected(the)) - fxSampleInstrumentation(the, 0, NULL); -#endif - { - // attempt to locate the "main" export from the host, and call it's function to start it - xsTry { - xsVar(0) = xsAwaitImport("main", XS_IMPORT_DEFAULT); - if (xsTest(xsVar(0))) { - if (xsIsInstanceOf(xsVar(0), xsFunctionPrototype)) { - xsCallFunction0(xsVar(0), xsGlobal); - } - } - } - xsCatch { - xsStringValue message = xsToString(xsException); - fprintf(stderr, "Uncaught error from VM: %s\n", message); - error = 1; - } - } - } - xsEndHost(the); - return error; -} - -/* - Terminates a running XS machine -*/ -void endMachine() { - xsDeleteMachine(machine); -} - -/* - Updates instrumentation (debugging statistics) for a running XS machine -*/ -void instrumentMachine() { -#ifdef mxDebug - xsBeginHost(machine); - { - // is the debugger connected? If not, skip to avoid console output - if (fxIsConnected(the)) - fxSampleInstrumentation(the, 0, NULL); - } - xsEndHost(the); -#endif -} - -/* - End point for XS to terminate execution -*/ -void fxAbort(xsMachine* the, int status) { - if (status == xsNotEnoughMemoryExit) - fprintf(stderr, "Abort: not enough memory\n"); - else if (status == xsStackOverflowExit) - fprintf(stderr, "Abort: stack overflow\n"); - else if (status == xsDeadStripExit) - fprintf(stderr, "Abort: dead strip\n"); - else if (status == xsUnhandledExceptionExit) - fprintf(stderr, "Abort: unhandled exception\n"); - else if (status != 0) - fprintf(stderr, "Abort: Error code %d\n", status); - exit(status); -} diff --git a/contributed/cli/x-cli-lin/machine.h b/contributed/cli/x-cli-lin/machine.h deleted file mode 100644 index ccfc881aa6..0000000000 --- a/contributed/cli/x-cli-lin/machine.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2020 Chris Midgley - * - * This file is part of the Moddable SDK Tools. - * - * The Moddable SDK Tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Moddable SDK Tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the Moddable SDK Tools. If not, see . - * - */ - -int startMachine(char *archivePath); -void endMachine(); -void instrumentMachine(); - diff --git a/contributed/cli/x-cli-lin/main.c b/contributed/cli/x-cli-lin/main.c index f5e8cdc740..59c81be24b 100644 --- a/contributed/cli/x-cli-lin/main.c +++ b/contributed/cli/x-cli-lin/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017 Chris Midgley + * Copyright (c) 2020 Chris Midgley * * This file is part of the Moddable SDK Tools. * @@ -20,18 +20,24 @@ /* This file implements a x-cli-lin platform for Moddable that supports an event loop and dynamically loaded - archives (mods). It implements the C main function, sets up XS machine and starts a Mac CFRunLoop message loop. - Upon a close message (which is intercepted and sent upon ^C) it cleanly shuts down the XS machine. It also - maintains the instrumentation updates, using a timer, on a once/second interval. + archives (mods). It implements the C main function, and starts up GTK with an invisible window to run + the actual program. It manages clearn termination upon receipt of ^C, and performs instrumentaton updates + once/second. + + This code is built upon GTK3 because the core of the Moddable "lin" platform is built upon GTK. This means + that this "cli" application will not work on SSH or headless Linux without installing X and likely using + xvfb (x frame buffer). + */ #include "xsAll.h" #include #include #include -#include "machine.h" +#include "cli.h" #include #include +#include static GtkApplication *gxApplication = NULL; static GtkWindow *gxWindow; @@ -39,7 +45,8 @@ static GtkApplication *app; #ifdef mxInstrument /* - Called from a once/second timer (see runMessageLoop) and is used to trigger instrumentation for debugging + Updates Moddable instrumentation once/second - called from GTK timer (see onApplicationActivate for where + the timer is started) */ gboolean sendInstrumentation(gpointer userData) { instrumentMachine(); @@ -47,7 +54,33 @@ gboolean sendInstrumentation(gpointer userData) { } #endif +/* + Map an archive (mod) into memory. Accepts the path to the archive, and returns either a pointer to the + memory mapped image, or NULL if there was a failure during the loading of the file. +*/ +void *loadArchive(char *archivePath) { + struct stat statbuf; + int archiveFile; + + archiveFile = open(archivePath, O_RDWR); + if (archiveFile < 0) { + fprintf(stderr, "Filed to load archive %s (error %s)\n", archivePath, strerror(errno)); + return NULL; + } + fstat(archiveFile, &statbuf); + void *archiveMapped = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, archiveFile, 0); + if (archiveMapped == MAP_FAILED) { + fprintf(stderr, "Filed to map archive %s (error %s)\n", archivePath, strerror(errno)); + return NULL; + } + return archiveMapped; +} + +/* + GTK handler for when the application is activated; starts up the VM and runs the main function, followed by + setting up a timer to update instrumentation once/second +*/ void onApplicationActivate(GtkApplication *app, gpointer it) { // start up our VM @@ -57,12 +90,19 @@ void onApplicationActivate(GtkApplication *app, gpointer it) g_timeout_add(1000, sendInstrumentation, NULL); } +/* + GTK handler for when the application is shutdown. Cleanly terminates the XS machine. +*/ void onApplicationShutdown(GtkApplication *app, gpointer it) { // done - end our XS machine endMachine(); } +/* + GTK handler for application startup. Creates a window, but does not show it, in order to keep the GTK + application running until we are ready for a shutdown +*/ void onApplicationStartup(GtkApplication *app) { // create a window to keep our application running, but don't show it (so we logically remain a console app) @@ -77,15 +117,10 @@ void ctrlHandler(int sig) { fprintf(stderr, "\nShutting down\n"); } - /* main - accepts a single optional command line argument that is the path to a mod to load Sets a ^C handler (for clearn shutdown) and starts up the GTK application - - Note: This depends on GTK, which also means X, as the Moddable 'lin' machine depends deeply on GTK. This means - that this "cli" application will not work on SSH or headless Linux without installing X and likely using - xvfb (x frame buffer). */ int main(int argc, char** argv) { diff --git a/contributed/cli/x-cli-mac/machine.h b/contributed/cli/x-cli-mac/machine.h deleted file mode 100644 index ccfc881aa6..0000000000 --- a/contributed/cli/x-cli-mac/machine.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2020 Chris Midgley - * - * This file is part of the Moddable SDK Tools. - * - * The Moddable SDK Tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Moddable SDK Tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the Moddable SDK Tools. If not, see . - * - */ - -int startMachine(char *archivePath); -void endMachine(); -void instrumentMachine(); - diff --git a/contributed/cli/x-cli-mac/main.c b/contributed/cli/x-cli-mac/main.c index bae09f425f..e3e0bf2e90 100644 --- a/contributed/cli/x-cli-mac/main.c +++ b/contributed/cli/x-cli-mac/main.c @@ -29,8 +29,10 @@ #include #include #include -#include "machine.h" +#include "cli.h" #include +#include +#include #ifdef mxInstrument /* @@ -41,6 +43,27 @@ static void sendInstrumentation(CFRunLoopTimerRef cfTimer, void *info) { } #endif +/* + Map an archive (mod) into memory. Accepts the path to the archive, and returns either a pointer to the + memory mapped image, or NULL if there was a failure during the loading of the file. +*/ +void *loadArchive(char *archivePath) { + struct stat statbuf; + int archiveFile; + + archiveFile = open(archivePath, O_RDWR); + if (archiveFile < 0) { + fprintf(stderr, "Filed to load archive %s (error %s)\n", archivePath, strerror(errno)); + return NULL; + } + fstat(archiveFile, &statbuf); + void *archiveMapped = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, archiveFile, 0); + if (archiveMapped == MAP_FAILED) { + fprintf(stderr, "Filed to map archive %s (error %s)\n", archivePath, strerror(errno)); + return NULL; + } + return archiveMapped; +} /* Message loop that manages the XS virtual machine. The machine is started up, a timer is created to update @@ -53,8 +76,7 @@ int runMessageLoop(char *pathToMod) // set up a timer for the instrumentation #ifdef mxInstrument - CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 1, - 1, 0, 0, sendInstrumentation, NULL); + CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 1, 1, 0, 0, sendInstrumentation, NULL); CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes); #endif diff --git a/contributed/cli/x-cli-win/machine.c b/contributed/cli/x-cli-win/machine.c deleted file mode 100644 index 1f3bf166bc..0000000000 --- a/contributed/cli/x-cli-win/machine.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2016-2020 Moddable Tech, Inc. and Chris Midgley - * - * This file is part of the Moddable SDK Runtime. - * - * The Moddable SDK Runtime is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Moddable SDK Runtime is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the Moddable SDK Runtime. If not, see . - * - */ - -/* - This file implements services for the x-cli-win platform to start/stop the XS virtual machine, provide loading of - archives (mods), and handling of instrumentation updates. -*/ - -#include "xsAll.h" -#include "mc.xs.h" - -HANDLE archiveFile = INVALID_HANDLE_VALUE; -HANDLE archiveMapping = INVALID_HANDLE_VALUE; -static txMachine root; -txMachine* machine = &root; - - -/* - Service used by fxMapArchive to read a section of the archive (mod) from memory -*/ -xsBooleanValue fxArchiveRead(void* src, size_t offset, void* buffer, size_t size) { - c_memcpy(buffer, ((txU1*)src) + offset, size); - return 1; -} - -/* - Service used by fxMapArchive to write a section of the archive (mod) in memory -*/ -xsBooleanValue fxArchiveWrite(void* dst, size_t offset, void* buffer, size_t size) { - c_memcpy(((txU1*)dst) + offset, buffer, size); - return 1; -} - -/* - Windows specific implementation to map an archive (mod) into memory. Accepts the path to the - archive, and returns either a pointer to the memory mapped image, or NULL if there was a failure during the loading - of the file. -*/ -void *loadArchive(char *archivePath) { - if (archivePath[0]) { - DWORD size; - archiveFile = CreateFile(archivePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (archiveFile == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed to open archive %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - size = GetFileSize(archiveFile, &size); - if (size == INVALID_FILE_SIZE) { - fprintf(stderr, "Failed to get file size for %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - archiveMapping = CreateFileMapping(archiveFile, NULL, PAGE_READWRITE, 0, (SIZE_T)size, NULL); - if (archiveMapping == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Failed to create file mapping for %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - void *memArchive = MapViewOfFile(archiveMapping, FILE_MAP_WRITE, 0, 0, (SIZE_T)size); - if (memArchive == NULL) { - fprintf(stderr, "Failed to map view of file for %s (error %d)\n", archivePath, GetLastError()); - return NULL; - } - return memArchive; - } - return NULL; -} - -/* - Callback function when the debugger is executed (see machine->onBreak). Updates the instrumentation so - breakpoints have accurate instrumentation just prior to stopping. -*/ -void debugBreak(xsMachine* the, uint8_t stop) -{ -#ifdef mxInstrument - if (stop) { - // fxCollectGarbage(the); - // the->garbageCollectionCount -= 1; - fxSampleInstrumentation(the, 0, NULL); - } -#endif -} - -/* - Starts up an XS machine, including loading and mapping the archive (mod) and calling the exported - function "main". -*/ -int startMachine(char *archivePath) { - int error = 0; - txPreparation* preparation = xsPreparation(); - void *memArchive = NULL; // memory mapped instance of the mod (archive) - void *archive = NULL; // XS symbol-mapped archive - - // memory map the archive using the first argument on the command line - if (archivePath) { - memArchive = loadArchive(archivePath); - } - - // map the symbols for the mod ("archive") - if (memArchive) { - archive = fxMapArchive(preparation, memArchive, memArchive, 4 * 1024, fxArchiveRead, fxArchiveWrite); - if (!archive) { - fprintf(stderr, "Failed to map the archive; continuing with no archive\n"); - } - } - - // instantiate the VM - machine = fxPrepareMachine(NULL, preparation, "machine", NULL, archive); - if (!machine) { - fprintf(stderr, "Failed to instantiate the VM\n"); - return 1; - } - - // set up to call our instrumentation update routing when we jump into the debugger - machine->onBreak = debugBreak; - - // set up the stack context for XS - xsBeginHost(machine); - { - xsVars(1); - -#ifdef mxInstrument - // send the instrumentation headers, only if the debugger is connected - if (fxIsConnected(the)) - fxDescribeInstrumentation(machine, 0, NULL, NULL); - - // send the initial instrumentation data, only if the debugger is connected - if (fxIsConnected(the)) - fxSampleInstrumentation(the, 0, NULL); -#endif - { - // attempt to locate the "main" export from the host, and call it's function to start it - xsTry { - xsVar(0) = xsAwaitImport("main", XS_IMPORT_DEFAULT); - if (xsTest(xsVar(0))) { - if (xsIsInstanceOf(xsVar(0), xsFunctionPrototype)) { - xsCallFunction0(xsVar(0), xsGlobal); - } - } - } - xsCatch { - xsStringValue message = xsToString(xsException); - fprintf(stderr, "Uncaught error from VM: %s\n", message); - error = 1; - } - } - } - xsEndHost(the); - return error; -} - -/* - Terminates a running XS machine -*/ -void endMachine() { - xsDeleteMachine(machine); -} - -/* - Updates instrumentation (debugging statistics) for a running XS machine -*/ -void instrumentMachine() { -#ifdef mxDebug - xsBeginHost(machine); - { - // is the debugger connected? If not, skip to avoid console output - if (fxIsConnected(the)) - fxSampleInstrumentation(the, 0, NULL); - } - xsEndHost(the); -#endif -} - -/* - End point for XS to terminate execution -*/ -void fxAbort(xsMachine* the, int status) { - if (status == xsNotEnoughMemoryExit) - fprintf(stderr, "Abort: not enough memory\n"); - else if (status == xsStackOverflowExit) - fprintf(stderr, "Abort: stack overflow\n"); - else if (status == xsDeadStripExit) - fprintf(stderr, "Abort: dead strip\n"); - else if (status == xsUnhandledExceptionExit) - fprintf(stderr, "Abort: unhandled exception\n"); - else if (status != 0) - fprintf(stderr, "Abort: Error code %d\n", status); - exit(status); -} diff --git a/contributed/cli/x-cli-win/main.c b/contributed/cli/x-cli-win/main.c index 2aae632057..302428e5ac 100644 --- a/contributed/cli/x-cli-win/main.c +++ b/contributed/cli/x-cli-win/main.c @@ -30,10 +30,12 @@ #include #include #include -#include "machine.h" +#include "cli.h" #include "sysinfoapi.h" unsigned int messagePumpThreadId = 0; // thread ID of the thread running the windows message pump + + #ifdef mxInstrument #define WM_APP_INSTRUMENTATION (WM_APP + 1) // ID of our private instrumentation message @@ -43,6 +45,42 @@ static VOID CALLBACK sendInstrumentationMessage(HWND hwnd, UINT uMsg, UINT_PTR i #endif +/* + Windows specific implementation to map an archive (mod) into memory. Accepts the path to the + archive, and returns either a pointer to the memory mapped image, or NULL if there was a failure during the loading + of the file. +*/ +void *loadArchive(char *archivePath) { + HANDLE archiveFile = INVALID_HANDLE_VALUE; + HANDLE archiveMapping = INVALID_HANDLE_VALUE; + + if (archivePath[0]) { + DWORD size; + archiveFile = CreateFile(archivePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (archiveFile == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to open archive %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + size = GetFileSize(archiveFile, &size); + if (size == INVALID_FILE_SIZE) { + fprintf(stderr, "Failed to get file size for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + archiveMapping = CreateFileMapping(archiveFile, NULL, PAGE_READWRITE, 0, (SIZE_T)size, NULL); + if (archiveMapping == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed to create file mapping for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + void *memArchive = MapViewOfFile(archiveMapping, FILE_MAP_WRITE, 0, 0, (SIZE_T)size); + if (memArchive == NULL) { + fprintf(stderr, "Failed to map view of file for %s (error %d)\n", archivePath, GetLastError()); + return NULL; + } + return memArchive; + } + return NULL; +} + /* Message pump that manages the XS virtual machine. The machine is started up, then the Windows message pump is executed allow for modules such as Timer to be used. Also maintains instrumentation to xsbug once From 86161742b69a2cae547132b3dd7160560aed8ae5 Mon Sep 17 00:00:00 2001 From: Chris Midgley Date: Sun, 27 Dec 2020 07:15:07 -0800 Subject: [PATCH 12/32] Added missing reference to fcntl --- contributed/cli/x-cli-lin/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/contributed/cli/x-cli-lin/main.c b/contributed/cli/x-cli-lin/main.c index 59c81be24b..0654440806 100644 --- a/contributed/cli/x-cli-lin/main.c +++ b/contributed/cli/x-cli-lin/main.c @@ -38,6 +38,7 @@ #include #include #include +#include static GtkApplication *gxApplication = NULL; static GtkWindow *gxWindow; From 9f941f127d6ea26481643c8eb5ff1a91e82de113 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 27 Dec 2020 11:20:18 -0400 Subject: [PATCH 13/32] Made shutdown messaging more consistent across platforms --- contributed/cli/x-cli-lin/main.c | 2 +- contributed/cli/x-cli-mac/main.c | 1 + contributed/cli/x-cli-win/main.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/contributed/cli/x-cli-lin/main.c b/contributed/cli/x-cli-lin/main.c index 0654440806..51c3c5d1e2 100644 --- a/contributed/cli/x-cli-lin/main.c +++ b/contributed/cli/x-cli-lin/main.c @@ -114,8 +114,8 @@ void onApplicationStartup(GtkApplication *app) Handler for intercepting the ctrl-C shutdown of the process, and instructs the CFRunLoop to shutdown */ void ctrlHandler(int sig) { - g_application_quit(G_APPLICATION(app)); fprintf(stderr, "\nShutting down\n"); + g_application_quit(G_APPLICATION(app)); } /* diff --git a/contributed/cli/x-cli-mac/main.c b/contributed/cli/x-cli-mac/main.c index e3e0bf2e90..de856d5d41 100644 --- a/contributed/cli/x-cli-mac/main.c +++ b/contributed/cli/x-cli-mac/main.c @@ -93,6 +93,7 @@ int runMessageLoop(char *pathToMod) Handler for intercepting the ctrl-C shutdown of the process, and instructs the CFRunLoop to shutdown */ void ctrlHandler(int sig) { + fprintf(stderr, "\nShutting down\n"); CFRunLoopStop(CFRunLoopGetCurrent()); } diff --git a/contributed/cli/x-cli-win/main.c b/contributed/cli/x-cli-win/main.c index 302428e5ac..208d76a7ef 100644 --- a/contributed/cli/x-cli-win/main.c +++ b/contributed/cli/x-cli-win/main.c @@ -141,6 +141,7 @@ BOOL WINAPI ctrlHandler(_In_ DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: + fprintf(stderr, "\nShutting down\n"); PostThreadMessage(messagePumpThreadId, WM_CLOSE, 0, 0); return TRUE; From 2e3d8a427a81c81e25a89453d225a3a9913e0cd8 Mon Sep 17 00:00:00 2001 From: Chris Midgley Date: Sun, 27 Dec 2020 08:49:45 -0800 Subject: [PATCH 14/32] Fixed mod loading in linux, and cleaned up some file formatting --- contributed/cli/cli.c | 12 +++------ contributed/cli/x-cli-lin/main.c | 46 +++++++++++++++++++------------- contributed/cli/x-cli-mac/main.c | 3 +-- contributed/cli/x-cli-win/main.c | 5 +--- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/contributed/cli/cli.c b/contributed/cli/cli.c index 005d5f71bc..006164d004 100644 --- a/contributed/cli/cli.c +++ b/contributed/cli/cli.c @@ -27,9 +27,7 @@ #include "mc.xs.h" #include "cli.h" -static txMachine root; -txMachine* machine = &root; - +txMachine* machine = NULL; /* Service used by fxMapArchive to read a section of the archive (mod) from memory @@ -47,14 +45,11 @@ xsBooleanValue fxArchiveWrite(void* dst, size_t offset, void* buffer, size_t siz return 1; } - - /* Callback function when the debugger is executed (see machine->onBreak). Updates the instrumentation so breakpoints have accurate instrumentation just prior to stopping. */ -void debugBreak(xsMachine* the, uint8_t stop) -{ +void debugBreak(xsMachine* the, uint8_t stop) { #ifdef mxInstrument if (stop) { // fxCollectGarbage(the); @@ -136,7 +131,8 @@ int startMachine(char *archivePath) { Terminates a running XS machine */ void endMachine() { - xsDeleteMachine(machine); + if (machine) + xsDeleteMachine(machine); } /* diff --git a/contributed/cli/x-cli-lin/main.c b/contributed/cli/x-cli-lin/main.c index 51c3c5d1e2..82536b1cc5 100644 --- a/contributed/cli/x-cli-lin/main.c +++ b/contributed/cli/x-cli-lin/main.c @@ -77,39 +77,47 @@ void *loadArchive(char *archivePath) { return archiveMapped; } +/* + GTK handler for when the application is shutdown. Cleanly terminates the XS machine. +*/ +void onApplicationShutdown(GtkApplication *app, gpointer it) { + // done - end our XS machine + endMachine(); +} /* - GTK handler for when the application is activated; starts up the VM and runs the main function, followed by - setting up a timer to update instrumentation once/second + GTK handler for application startup, which is the first event we process when the app starts up. Creates a window (but does not show it) + in order to keep the GTK application running until we are ready for a shutdown. Also sets up the instrumentation timer (once/second for + instrumentation updates in the debugger) */ -void onApplicationActivate(GtkApplication *app, gpointer it) -{ - // start up our VM - startMachine(NULL); +void onApplicationStartup(GtkApplication *app) { + // create a window to keep our application running, but don't show it (so we logically remain a console app) + gxWindow = (GtkWindow*)gtk_application_window_new(app); // set up a timer for instrumentation updates once/second +#ifdef mxInstrument g_timeout_add(1000, sendInstrumentation, NULL); +#endif } /* - GTK handler for when the application is shutdown. Cleanly terminates the XS machine. + GTK handler for when the application is activated, which happens if there are no commmand line arguments. We simply start up the + VM with no mods. */ -void onApplicationShutdown(GtkApplication *app, gpointer it) -{ - // done - end our XS machine - endMachine(); +void onApplicationActivate(GtkApplication *app, gpointer it) { + startMachine(NULL); + } /* - GTK handler for application startup. Creates a window, but does not show it, in order to keep the GTK - application running until we are ready for a shutdown + GTK handler for when a command line is provided. We start up the VM using the path to the mod from the command line */ -void onApplicationStartup(GtkApplication *app) -{ - // create a window to keep our application running, but don't show it (so we logically remain a console app) - gxWindow = (GtkWindow*)gtk_application_window_new(app); +void onApplicationOpen(GtkApplication *app, GFile **files, gint c, const gchar *hint, gpointer it) { + // start up our VM, optionally with path to archive (mod) + startMachine(g_file_get_path(files[0])); } + /* Handler for intercepting the ctrl-C shutdown of the process, and instructs the CFRunLoop to shutdown */ @@ -123,8 +131,7 @@ void ctrlHandler(int sig) { Sets a ^C handler (for clearn shutdown) and starts up the GTK application */ -int main(int argc, char** argv) -{ +int main(int argc, char** argv) { int status; // take control over ^C handling @@ -134,6 +141,7 @@ int main(int argc, char** argv) g_signal_connect(app, "startup", G_CALLBACK(onApplicationStartup), NULL); g_signal_connect(app, "activate", G_CALLBACK(onApplicationActivate), NULL); g_signal_connect(app, "shutdown", G_CALLBACK(onApplicationShutdown), NULL); + g_signal_connect(app, "open", G_CALLBACK(onApplicationOpen), NULL); status = g_application_run(G_APPLICATION(app), argc, argv); g_object_unref(app); diff --git a/contributed/cli/x-cli-mac/main.c b/contributed/cli/x-cli-mac/main.c index de856d5d41..c6fb3581d6 100644 --- a/contributed/cli/x-cli-mac/main.c +++ b/contributed/cli/x-cli-mac/main.c @@ -69,8 +69,7 @@ void *loadArchive(char *archivePath) { Message loop that manages the XS virtual machine. The machine is started up, a timer is created to update instrumentation every second, and then the Mac message loop is executed. */ -int runMessageLoop(char *pathToMod) -{ +int runMessageLoop(char *pathToMod) { // start up our VM int error = startMachine(pathToMod); diff --git a/contributed/cli/x-cli-win/main.c b/contributed/cli/x-cli-win/main.c index 208d76a7ef..cce9bf205b 100644 --- a/contributed/cli/x-cli-win/main.c +++ b/contributed/cli/x-cli-win/main.c @@ -35,7 +35,6 @@ unsigned int messagePumpThreadId = 0; // thread ID of the thread running the windows message pump - #ifdef mxInstrument #define WM_APP_INSTRUMENTATION (WM_APP + 1) // ID of our private instrumentation message @@ -44,7 +43,6 @@ static VOID CALLBACK sendInstrumentationMessage(HWND hwnd, UINT uMsg, UINT_PTR i } #endif - /* Windows specific implementation to map an archive (mod) into memory. Accepts the path to the archive, and returns either a pointer to the memory mapped image, or NULL if there was a failure during the loading @@ -87,8 +85,7 @@ void *loadArchive(char *archivePath) { per second, triggered by the WM_APP_INSTRUMENTATION message from a timer. Shuts down the VM when a WM_CLOSE message is received, and signals completion using the terminateEvent event. */ -void messagePump(char *pathToMod) -{ +void messagePump(char *pathToMod) { MSG msg; // save away our thread ID - this is done so that the ^C interception can send us a WM_CLOSE message From 3617fc12be39ac1c2b81300aa0a090c7d90c6455 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 27 Dec 2020 13:14:29 -0400 Subject: [PATCH 15/32] Improved manifest to support building any platform, and updated README --- contributed/cli/README.md | 21 ++++++++++++++++++++- contributed/cli/manifest.json | 30 +++++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/contributed/cli/README.md b/contributed/cli/README.md index 46d71c99eb..8c452e92e0 100644 --- a/contributed/cli/README.md +++ b/contributed/cli/README.md @@ -17,6 +17,11 @@ manifest file: ], ``` +Adding this manifest for non-command-line platforms (such as `-p esp32` or `-p win`) will not affect your program (the +manifest does not include any modules). However, when your platform is one of `x-cli-win`, `x-cli-lin`, or +`x-cli-mac`, it will add the appropriate logic to build the platfrom as a native console executuable for that +platform. + ## Running your program When you build, such as `mcconfig -m -d -p x-cli-win`, the resulting program will be a native app (such as `.exe` on @@ -40,4 +45,18 @@ via the `mcrun` program while a host waits for the module to be presented), but ## Using the debugger and instrumentation Full support for the debugger and instrumentation is included, and it should behave the same as using other platform -types. Instrumentation is updated once per second. \ No newline at end of file +types. Instrumentation is updated once per second. + +## Linux requires X Windows System + +The Moddable implementation for Linux depends on the GTK3+ libraries, and as such even though a console application is +built using `cli`, it still depends on X being installed. This means that running the Linux console application from +`telnet` or `ssh`, or from a server-based (non-desktop) Linux distro will not work. You should be able to execute it +by installing X and also using the `xvfb` module (which implements a headless X frame buffer), but this has not been +tested yet. If you try this and find a recipe that works, please submit a pull and update this documentation +accordingly. + +A great future project for someone is to consider implementing a generic console machine across all of Moddable using +the `libuv` event handler, which is the event handler from Node. It is cross-platform and should allow for building +command line programs on a wide range of platforms without the need for X or any window manager, assuming other +cross-platform libraries are also consumed in the process for operations like files, resources, etc. diff --git a/contributed/cli/manifest.json b/contributed/cli/manifest.json index 892efdc021..2533d22969 100644 --- a/contributed/cli/manifest.json +++ b/contributed/cli/manifest.json @@ -1,8 +1,28 @@ { - "modules": { - "*": [ - "./$(PLATFORM)/main", - "./cli" - ] + "platforms": { + "x-cli-win": { + "modules": { + "*": [ + "./$(PLATFORM)/main", + "./cli" + ] + } + }, + "x-cli-mac": { + "modules": { + "*": [ + "./$(PLATFORM)/main", + "./cli" + ] + } + }, + "x-cli-lin": { + "modules": { + "*": [ + "./$(PLATFORM)/main", + "./cli" + ] + } + } } } \ No newline at end of file From 8a5848ef8088379d9a61b084a94876bbafccf0ae Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 28 Dec 2020 09:06:43 -0400 Subject: [PATCH 16/32] Test for debugger connect on instrumentation (cleans output on x-cli-XXX platforms) --- modules/base/worker/pcWorker.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/base/worker/pcWorker.c b/modules/base/worker/pcWorker.c index 3702f945bb..8d03e2db32 100644 --- a/modules/base/worker/pcWorker.c +++ b/modules/base/worker/pcWorker.c @@ -1,3 +1,4 @@ +#include "xsAll.h" #include "mc.xs.h" #include "screen.h" @@ -103,7 +104,8 @@ void fxWorkerInitialize(txWorker* worker) } xsEndHost(worker->machine); #if mxInstrument - fxDescribeInstrumentation(worker->machine, 0, NULL, NULL); + if (fxIsConnected(worker->machine)) + fxDescribeInstrumentation(worker->machine, 0, NULL, NULL); #endif mxLockMutex(&worker->runningMutex); worker->running = 1; @@ -129,7 +131,8 @@ void fxWorkerMessage(void* machine, void* it) xsEndHost(machine); #if mxInstrument if (((txScreen*)(((xsMachine*)machine)->host))->mainThread != mxCurrentThread()) - fxSampleInstrumentation(machine, 0, NULL); + if (fxIsConnected(machine)) + fxSampleInstrumentation(machine, 0, NULL); #endif c_free(job->argument); } From d59d3875d784e750dc4888529d56c1f3215b4409 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 28 Dec 2020 09:08:48 -0400 Subject: [PATCH 17/32] Implemented support for workers --- contributed/cli/cli.c | 23 ++++++-- contributed/cli/screen.h | 112 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 contributed/cli/screen.h diff --git a/contributed/cli/cli.c b/contributed/cli/cli.c index 006164d004..deb97d3302 100644 --- a/contributed/cli/cli.c +++ b/contributed/cli/cli.c @@ -26,8 +26,12 @@ #include "xsAll.h" #include "mc.xs.h" #include "cli.h" +#include "screen.h" -txMachine* machine = NULL; +// txMachine* machine = NULL; +// set up context (using a txScreen, from screen.h, because that is what the base/Worker module needs - it is +// a subset of what a simulator would use, containing mostly support for finding the machine and mutex controls) +txScreen screen; /* Service used by fxMapArchive to read a section of the archive (mod) from memory @@ -82,8 +86,13 @@ int startMachine(char *archivePath) { } } + // set up our "screen" context + mxCreateMutex(&screen.workersMutex); + screen.firstWorker = NULL; + screen.mainThread = mxCurrentThread(); + // instantiate the VM - machine = fxPrepareMachine(NULL, preparation, "machine", NULL, archive); + txMachine *machine = fxPrepareMachine(NULL, preparation, "machine", &screen, archive); if (!machine) { fprintf(stderr, "Failed to instantiate the VM\n"); return 1; @@ -92,6 +101,10 @@ int startMachine(char *archivePath) { // instruct the machine to call us prior to entering the debugger, so we can update instrumentation machine->onBreak = debugBreak; + // link our screen and machine objects together + screen.machine = (void *) machine; + machine->host = (void *) &screen; + // set up the stack context for XS xsBeginHost(machine); { @@ -131,8 +144,8 @@ int startMachine(char *archivePath) { Terminates a running XS machine */ void endMachine() { - if (machine) - xsDeleteMachine(machine); + if (screen.machine) + xsDeleteMachine(screen.machine); } /* @@ -140,7 +153,7 @@ void endMachine() { */ void instrumentMachine() { #ifdef mxDebug - xsBeginHost(machine); + xsBeginHost(screen.machine); { // is the debugger connected? If not, skip to avoid console output if (fxIsConnected(the)) diff --git a/contributed/cli/screen.h b/contributed/cli/screen.h new file mode 100644 index 0000000000..181a6206e6 --- /dev/null +++ b/contributed/cli/screen.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016-2018 Moddable Tech, Inc. + * + * This file is part of the Moddable SDK Tools. + * + * The Moddable SDK Tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Moddable SDK Tools. If not, see . + * + */ + +#include +#if mxLinux +#include +#elif mxWindows +#include +#else +#include "pthread.h" +#endif + +#if mxLinux + typedef GCond txCondition; + typedef GMutex txMutex; + typedef GThread* txThread; + #define mxCreateCondition(CONDITION) g_cond_init(CONDITION) + #define mxCreateMutex(MUTEX) g_mutex_init(MUTEX) + #define mxCurrentThread() g_thread_self() + #define mxDeleteCondition(CONDITION) g_cond_clear(CONDITION) + #define mxDeleteMutex(MUTEX) g_mutex_clear(MUTEX) + #define mxLockMutex(MUTEX) g_mutex_lock(MUTEX) + #define mxSignalCondition(CONDITION) g_cond_signal(CONDITION) + #define mxUnlockMutex(MUTEX) g_mutex_unlock(MUTEX) + #define mxWaitCondition(CONDITION,MUTEX) g_cond_wait(CONDITION,MUTEX) +#elif mxWindows + typedef CONDITION_VARIABLE txCondition; + typedef CRITICAL_SECTION txMutex; + typedef DWORD txThread; + #define mxCreateCondition(CONDITION) InitializeConditionVariable(CONDITION) + #define mxCreateMutex(MUTEX) InitializeCriticalSection(MUTEX) + #define mxCurrentThread() GetCurrentThreadId() + #define mxDeleteCondition(CONDITION) (void)(CONDITION) + #define mxDeleteMutex(MUTEX) DeleteCriticalSection(MUTEX) + #define mxLockMutex(MUTEX) EnterCriticalSection(MUTEX) + #define mxSignalCondition(CONDITION) WakeConditionVariable(CONDITION) + #define mxUnlockMutex(MUTEX) LeaveCriticalSection(MUTEX) + #define mxWaitCondition(CONDITION,MUTEX) SleepConditionVariableCS(CONDITION,MUTEX,INFINITE) +#else + typedef pthread_cond_t txCondition; + typedef pthread_mutex_t txMutex; + typedef pthread_t txThread; + #define mxCreateCondition(CONDITION) pthread_cond_init(CONDITION,NULL) + #define mxCreateMutex(MUTEX) pthread_mutex_init(MUTEX,NULL) + #define mxCurrentThread() pthread_self() + #define mxDeleteCondition(CONDITION) pthread_cond_destroy(CONDITION) + #define mxDeleteMutex(MUTEX) pthread_mutex_destroy(MUTEX) + #define mxLockMutex(MUTEX) pthread_mutex_lock(MUTEX) + #define mxSignalCondition(CONDITION) pthread_cond_signal(CONDITION) + #define mxUnlockMutex(MUTEX) pthread_mutex_unlock(MUTEX) + #define mxWaitCondition(CONDITION,MUTEX) pthread_cond_wait(CONDITION,MUTEX) +#endif + + +typedef struct sxScreen txScreen; + + + +struct sxScreen { + void *machine; + void *firstWorker; + txMutex workersMutex; + txThread mainThread; + + + + // void* view; + // void* archive; + // txScreenAbortProc abort; + // txScreenBufferChangedProc bufferChanged; + // txScreenFormatChangedProc formatChanged; + // txScreenIdleProc idle; + // txScreenMessageProc invoke; + // txScreenKeyProc key; + // txScreenMessageProc post; + // txScreenQuitProc quit; + // txScreenStartProc start; + // txScreenStopProc stop; + // txScreenTouchProc touch; + // int flags; + // long instrumentTime; + // int pixelFormat; + // int rotation; + // int width; + // int height; + // uint16_t *clut; + // uint8_t palette[16 * screenBytesPerPixel]; + // void *frameBuffer; // only used when kPocoFrameBuffer + // uint32_t frameBufferLength; // only used when kPocoFrameBuffer + // unsigned char *rowAddress; + // int rowCount; + // int rowDelta; + // int rowIndex; + // unsigned char buffer[1]; +}; \ No newline at end of file From 35bce854126deae13b752298e2ff51b7a44585c9 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 28 Dec 2020 09:09:52 -0400 Subject: [PATCH 18/32] Added missing module reference --- examples/base/instrumentation/instrumentation/manifest.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/base/instrumentation/instrumentation/manifest.json b/examples/base/instrumentation/instrumentation/manifest.json index c79a80c629..58542af242 100644 --- a/examples/base/instrumentation/instrumentation/manifest.json +++ b/examples/base/instrumentation/instrumentation/manifest.json @@ -2,7 +2,8 @@ "include": "$(MODDABLE)/examples/manifest_base.json", "modules": { "*": [ - "./main" + "./main", + "$(MODULES)/base/instrumentation/*" ] } } From af67c3f8ac93290107276b9d3d8f08622248c0d0 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 28 Dec 2020 09:10:22 -0400 Subject: [PATCH 19/32] Support for x-cli-XXX platforms --- examples/manifest_cli.json | 40 ++++++++++++++++++++++++++++++ examples/network/net/manifest.json | 3 +++ modules/base/worker/manifest.json | 15 +++++++++++ 3 files changed, 58 insertions(+) create mode 100644 examples/manifest_cli.json diff --git a/examples/manifest_cli.json b/examples/manifest_cli.json new file mode 100644 index 0000000000..38823b7f19 --- /dev/null +++ b/examples/manifest_cli.json @@ -0,0 +1,40 @@ +{ + "include": [ + "$(MODDABLE)/contributed/cli/manifest.json" + ], + "modules": { + "*": [ + "$(MODULES)/base/timer/timer" + ] + }, + "preload": [ + ], + "platforms": { + "x-cli-win": { + "modules": { + "*": [ + "$(MODULES)/files/preference/win/*", + "$(MODULES)/base/timer/modTimer", + "$(MODULES)/base/timer/win/*" + ] + } + }, + "x-cli-lin": { + "modules": { + "*": [ + "$(MODULES)/files/preference/lin/*", + "$(MODULES)/base/timer/lin/*" + ] + } + }, + "x-cli-mac": { + "modules": { + "*": [ + "$(MODULES)/files/preference/mac/*", + "$(MODULES)/base/timer/modTimer", + "$(MODULES)/base/timer/mac/*" + ] + } + } + } +} diff --git a/examples/network/net/manifest.json b/examples/network/net/manifest.json index 1d95cd2a8f..084fc954b7 100644 --- a/examples/network/net/manifest.json +++ b/examples/network/net/manifest.json @@ -15,6 +15,9 @@ "qca4020": {}, "mac": {}, "win": {}, + "x-cli-win": {}, + "x-cli-lin": {}, + "x-cli-mac": {}, "...": { "error": "Net module unsupported" } diff --git a/modules/base/worker/manifest.json b/modules/base/worker/manifest.json index ce32cc986d..6395d076c7 100644 --- a/modules/base/worker/manifest.json +++ b/modules/base/worker/manifest.json @@ -34,6 +34,21 @@ "*": "$(MODULES)/base/worker/pcWorker" } }, + "x-cli-lin": { + "modules": { + "*": "$(MODULES)/base/worker/pcWorker" + } + }, + "x-cli-mac": { + "modules": { + "*": "$(MODULES)/base/worker/pcWorker" + } + }, + "x-cli-win": { + "modules": { + "*": "$(MODULES)/base/worker/pcWorker" + } + }, "...": { "error": "Worker module unsupported" } From a97c641191b0ef2c28509e5a8490add95fa58495 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 28 Dec 2020 10:26:37 -0400 Subject: [PATCH 20/32] Refactored to switch from "x-cli-XXX" to "cli-XXX" --- contributed/cli/README.md | 29 +-- contributed/cli/{x-cli-lin => cli-lin}/main.c | 2 +- contributed/cli/{x-cli-mac => cli-mac}/main.c | 2 +- contributed/cli/{x-cli-win => cli-win}/main.c | 2 +- contributed/cli/cli.c | 2 +- contributed/cli/manifest.json | 6 +- examples/manifest_base.json | 9 + examples/manifest_cli.json | 6 +- examples/manifest_net.json | 6 +- examples/network/net/manifest.json | 6 +- modules/base/worker/manifest.json | 6 +- modules/files/file/manifest.json | 6 +- modules/files/preference/manifest.json | 4 +- modules/network/wifi/manifest.json | 6 +- tools/mcconfig.js | 8 +- .../{make.x-cli-lin.mk => make.cli-lin.mk} | 0 tools/mcconfig/make.cli-mac.mk | 177 ++++++++++++++++ tools/mcconfig/make.x-cli-mac.mk | 19 +- tools/mcconfig/nmake.cli-win.mk | 200 ++++++++++++++++++ tools/mcconfig/nmake.x-cli-win.mk | 16 +- tools/mcmanifest.js | 2 +- .../{make.x-cli-lin.mk => make.cli-lin.mk} | 0 .../{make.x-cli-mac.mk => make.cli-mac.mk} | 0 .../{nmake.x-cli-win.mk => nmake.cli-win.mk} | 0 24 files changed, 435 insertions(+), 79 deletions(-) rename contributed/cli/{x-cli-lin => cli-lin}/main.c (97%) rename contributed/cli/{x-cli-mac => cli-mac}/main.c (97%) rename contributed/cli/{x-cli-win => cli-win}/main.c (98%) rename tools/mcconfig/{make.x-cli-lin.mk => make.cli-lin.mk} (100%) create mode 100644 tools/mcconfig/make.cli-mac.mk create mode 100644 tools/mcconfig/nmake.cli-win.mk rename tools/mcrun/{make.x-cli-lin.mk => make.cli-lin.mk} (100%) rename tools/mcrun/{make.x-cli-mac.mk => make.cli-mac.mk} (100%) rename tools/mcrun/{nmake.x-cli-win.mk => nmake.cli-win.mk} (100%) diff --git a/contributed/cli/README.md b/contributed/cli/README.md index 8c452e92e0..c1b312c7ee 100644 --- a/contributed/cli/README.md +++ b/contributed/cli/README.md @@ -1,30 +1,12 @@ # Command line (cli) controller -Moddable is able to provide command line programs using the `x-cli-` platform type, including `x-cli-win` for -Windows, `x-cli-mac` for Mac, and `x-cli-lin` for Linux. When using this code, you are normally responsible for -creating your own main code and support services for moddable. This package provides an implementation of the command -line interfaces for Moddable, including support for the event loop and host/mod loading. - -## Configuring the manifest - -To have your Moddable program use this command line interface, you simply update the `include` section to add the `cli` -manifest file: - -``` -"include": [ - ... other includes ... - "$(MODDABLE)/contributed/cli/manifest.json" -], -``` - -Adding this manifest for non-command-line platforms (such as `-p esp32` or `-p win`) will not affect your program (the -manifest does not include any modules). However, when your platform is one of `x-cli-win`, `x-cli-lin`, or -`x-cli-mac`, it will add the appropriate logic to build the platfrom as a native console executuable for that -platform. +Extends Moddable to be able to provide command line program using the `cli-` platform type, including +`cli-win` for Windows, `cli-mac` for Mac, and `cli-lin` for Linux. Includes support host/mod loading, timers, +promises and workers. ## Running your program -When you build, such as `mcconfig -m -d -p x-cli-win`, the resulting program will be a native app (such as `.exe` on +When you build, such as `mcconfig -m -d -p cli-win`, the resulting program will be a native app (such as `.exe` on windows, or `.app` on mac). If you run that program with no command line arguments, the default exported `main` function will be called. The code will continue to operate, including support for Timer and other async services. If you need to terminate the app under control of the program, use: @@ -40,7 +22,8 @@ fxAbort(status); // status is the exit code the program will terminate with It you specify a path to a mod file (`.xsa` file, built with `mcrun`) as the first argument to the program, it will be loaded and symbols resolved before the `main` exported function is called. This is slightly different than how the microcontrollers consume mods (from the flash `xs` partition, upon reboot) or how the simulators consume mods (provided -via the `mcrun` program while a host waits for the module to be presented), but the resulting functionality remains the same. +via the `mcrun` program while a host waits for the module to be presented), but the resulting functionality remains +the same. ## Using the debugger and instrumentation diff --git a/contributed/cli/x-cli-lin/main.c b/contributed/cli/cli-lin/main.c similarity index 97% rename from contributed/cli/x-cli-lin/main.c rename to contributed/cli/cli-lin/main.c index 82536b1cc5..d2bbb2b093 100644 --- a/contributed/cli/x-cli-lin/main.c +++ b/contributed/cli/cli-lin/main.c @@ -19,7 +19,7 @@ */ /* - This file implements a x-cli-lin platform for Moddable that supports an event loop and dynamically loaded + This file implements a cli-lin platform for Moddable that supports an event loop and dynamically loaded archives (mods). It implements the C main function, and starts up GTK with an invisible window to run the actual program. It manages clearn termination upon receipt of ^C, and performs instrumentaton updates once/second. diff --git a/contributed/cli/x-cli-mac/main.c b/contributed/cli/cli-mac/main.c similarity index 97% rename from contributed/cli/x-cli-mac/main.c rename to contributed/cli/cli-mac/main.c index c6fb3581d6..b548ec0eac 100644 --- a/contributed/cli/x-cli-mac/main.c +++ b/contributed/cli/cli-mac/main.c @@ -19,7 +19,7 @@ */ /* - This file implements a x-cli-mac platform for Moddable that supports an event loop and dynamically loaded + This file implements a cli-mac platform for Moddable that supports an event loop and dynamically loaded archives (mods). It implements the C main function, sets up XS machine and starts a Mac CFRunLoop message loop. Upon a close message (which is intercepted and sent upon ^C) it cleanly shuts down the XS machine. It also maintains the instrumentation updates, using a timer, on a once/second interval. diff --git a/contributed/cli/x-cli-win/main.c b/contributed/cli/cli-win/main.c similarity index 98% rename from contributed/cli/x-cli-win/main.c rename to contributed/cli/cli-win/main.c index cce9bf205b..0594e1fea1 100644 --- a/contributed/cli/x-cli-win/main.c +++ b/contributed/cli/cli-win/main.c @@ -19,7 +19,7 @@ */ /* - This file implements a x-cli-win platform for Moddable that supports an event loop and dynamically loaded + This file implements a cli-win platform for Moddable that supports an event loop and dynamically loaded archives (mods). It implements the C main function, sets up XS machine and starts a Windows message pump. Upon a WM_CLOSE message (which is intercepted and sent upon ^C) it cleanly shuts down the XS machine. It also maintains the instrumentation updates, using a timer, on a once/second interval. diff --git a/contributed/cli/cli.c b/contributed/cli/cli.c index deb97d3302..086e5d4db5 100644 --- a/contributed/cli/cli.c +++ b/contributed/cli/cli.c @@ -19,7 +19,7 @@ */ /* - This file implements common services across all platforms to implement the "x-cli-XXX" runtime for Moddable, + This file implements common services across all platforms to implement the "cli-XXX" runtime for Moddable, including support for starting/stopping the XS virtual machine, and providing loading of archives (mods). */ diff --git a/contributed/cli/manifest.json b/contributed/cli/manifest.json index 2533d22969..583ee3f9cd 100644 --- a/contributed/cli/manifest.json +++ b/contributed/cli/manifest.json @@ -1,6 +1,6 @@ { "platforms": { - "x-cli-win": { + "cli-win": { "modules": { "*": [ "./$(PLATFORM)/main", @@ -8,7 +8,7 @@ ] } }, - "x-cli-mac": { + "cli-mac": { "modules": { "*": [ "./$(PLATFORM)/main", @@ -16,7 +16,7 @@ ] } }, - "x-cli-lin": { + "cli-lin": { "modules": { "*": [ "./$(PLATFORM)/main", diff --git a/examples/manifest_base.json b/examples/manifest_base.json index ebd484bca1..f48d7dd673 100644 --- a/examples/manifest_base.json +++ b/examples/manifest_base.json @@ -68,6 +68,15 @@ "win": { "include": "$(BUILD_SIMULATOR)/manifest.json" }, + "cli-lin": { + "include": "$(MODDABLE)/examples/manifest_cli.json" + }, + "cli-mac": { + "include": "$(MODDABLE)/examples/manifest_cli.json" + }, + "cli-win": { + "include": "$(MODDABLE)/examples/manifest_cli.json" + }, "wasm": { "include": "$(BUILD_SIMULATOR)/manifest.json" } diff --git a/examples/manifest_cli.json b/examples/manifest_cli.json index 38823b7f19..17ba8e0098 100644 --- a/examples/manifest_cli.json +++ b/examples/manifest_cli.json @@ -10,7 +10,7 @@ "preload": [ ], "platforms": { - "x-cli-win": { + "cli-win": { "modules": { "*": [ "$(MODULES)/files/preference/win/*", @@ -19,7 +19,7 @@ ] } }, - "x-cli-lin": { + "cli-lin": { "modules": { "*": [ "$(MODULES)/files/preference/lin/*", @@ -27,7 +27,7 @@ ] } }, - "x-cli-mac": { + "cli-mac": { "modules": { "*": [ "$(MODULES)/files/preference/mac/*", diff --git a/examples/manifest_net.json b/examples/manifest_net.json index f70af010ea..d298f61360 100644 --- a/examples/manifest_net.json +++ b/examples/manifest_net.json @@ -83,7 +83,7 @@ "net" ] }, - "x-cli-win": { + "cli-win": { "modules": { "*": [ "$(MODULES)/network/socket/*", @@ -99,7 +99,7 @@ "net" ] }, - "x-cli-mac": { + "cli-mac": { "modules": { "*": [ "$(MODULES)/network/socket/*", @@ -115,7 +115,7 @@ "net" ] }, - "x-cli-lin": { + "cli-lin": { "modules": { "*": [ "$(MODULES)/network/socket/*", diff --git a/examples/network/net/manifest.json b/examples/network/net/manifest.json index 084fc954b7..ed30cdbf15 100644 --- a/examples/network/net/manifest.json +++ b/examples/network/net/manifest.json @@ -15,9 +15,9 @@ "qca4020": {}, "mac": {}, "win": {}, - "x-cli-win": {}, - "x-cli-lin": {}, - "x-cli-mac": {}, + "cli-win": {}, + "cli-lin": {}, + "cli-mac": {}, "...": { "error": "Net module unsupported" } diff --git a/modules/base/worker/manifest.json b/modules/base/worker/manifest.json index 6395d076c7..60597e596c 100644 --- a/modules/base/worker/manifest.json +++ b/modules/base/worker/manifest.json @@ -34,17 +34,17 @@ "*": "$(MODULES)/base/worker/pcWorker" } }, - "x-cli-lin": { + "cli-lin": { "modules": { "*": "$(MODULES)/base/worker/pcWorker" } }, - "x-cli-mac": { + "cli-mac": { "modules": { "*": "$(MODULES)/base/worker/pcWorker" } }, - "x-cli-win": { + "cli-win": { "modules": { "*": "$(MODULES)/base/worker/pcWorker" } diff --git a/modules/files/file/manifest.json b/modules/files/file/manifest.json index 15f5ae9160..b804c2f1d4 100644 --- a/modules/files/file/manifest.json +++ b/modules/files/file/manifest.json @@ -34,7 +34,7 @@ } } }, - "x-cli-mac": { + "cli-mac": { "modules": { "*": "$(MODULES)/files/file/mac/*" }, @@ -54,7 +54,7 @@ } } }, - "x-cli-win": { + "cli-win": { "modules": { "*": "$(MODULES)/files/file/win/*" }, @@ -74,7 +74,7 @@ } } }, - "x-cli-lin": { + "cli-lin": { "modules": { "*": "$(MODULES)/files/file/lin/*" }, diff --git a/modules/files/preference/manifest.json b/modules/files/preference/manifest.json index 4feaf60a07..b6352a0b3f 100644 --- a/modules/files/preference/manifest.json +++ b/modules/files/preference/manifest.json @@ -36,7 +36,7 @@ ] } }, - "x-cli-mac": { + "cli-mac": { "modules": { "*": [ "$(MODULES)/files/preference/mac/*" @@ -50,7 +50,7 @@ ] } }, - "x-cli-win": { + "cli-win": { "modules": { "*": [ "$(MODULES)/files/preference/win/*" diff --git a/modules/network/wifi/manifest.json b/modules/network/wifi/manifest.json index b66bcdc4d8..965c2c1a82 100644 --- a/modules/network/wifi/manifest.json +++ b/modules/network/wifi/manifest.json @@ -23,7 +23,7 @@ ] } }, - "x-cli-lin": { + "cli-lin": { "modules": { "*": [ "$(MODULES)/network/wifi/sim/*" @@ -37,7 +37,7 @@ ] } }, - "x-cli-mac": { + "cli-mac": { "modules": { "*": [ "$(MODULES)/network/wifi/sim/*" @@ -51,7 +51,7 @@ ] } }, - "x-cli-win": { + "cli-win": { "modules": { "*": [ "$(MODULES)/network/wifi/sim/*" diff --git a/tools/mcconfig.js b/tools/mcconfig.js index bc4a1d3d3e..6641616bd2 100644 --- a/tools/mcconfig.js +++ b/tools/mcconfig.js @@ -782,6 +782,10 @@ export default class extends Tool { path += this.slash + platform.slice(2); this.createDirectory(path); } + else if (platform.startsWith("cli-")) { + path += this.slash + platform.slice(4); + this.createDirectory(path); + } else { path += this.slash + this.platform; this.createDirectory(path); @@ -1029,7 +1033,7 @@ export default class extends Tool { var name = this.environment.NAME if (this.platform == "x-mac") this.binPath = this.createDirectories(this.outputPath, "bin", name + ".app"); - else if ((this.platform == "x-lin") || (this.platform == "x-win") || (this.platform.startsWith("x-cli-"))) + else if ((this.platform == "x-lin") || (this.platform == "x-win") || (this.platform.startsWith("x-cli-") || (this.platform.startsWith("cli-")))) this.binPath = this.createDirectories(this.outputPath, "bin"); else this.binPath = this.createDirectories(this.outputPath, "bin", name); @@ -1095,6 +1099,8 @@ export default class extends Tool { this.createDirectory(this.resourcesPath); } else if (this.platform.startsWith("x-cli-")) { + } + else if (this.platform.startsWith("cli-")) { var folder = "mc", file; this.createDirectory(this.modulesPath + this.slash + folder); var source = this.tmpPath + this.slash + "mc.config.js"; diff --git a/tools/mcconfig/make.x-cli-lin.mk b/tools/mcconfig/make.cli-lin.mk similarity index 100% rename from tools/mcconfig/make.x-cli-lin.mk rename to tools/mcconfig/make.cli-lin.mk diff --git a/tools/mcconfig/make.cli-mac.mk b/tools/mcconfig/make.cli-mac.mk new file mode 100644 index 0000000000..3c482be282 --- /dev/null +++ b/tools/mcconfig/make.cli-mac.mk @@ -0,0 +1,177 @@ +# +# Copyright (c) 2016-2020 Moddable Tech, Inc. +# +# This file is part of the Moddable SDK Tools. +# +# The Moddable SDK Tools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# The Moddable SDK Tools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Moddable SDK Tools. If not, see . +# + +ifeq ($(DEBUG),1) + LIB_DIR = $(BUILD_DIR)/tmp/mac/debug/lib +else + ifeq ($(INSTRUMENT),1) + LIB_DIR = $(BUILD_DIR)/tmp/mac/instrument/lib + else + LIB_DIR = $(BUILD_DIR)/tmp/mac/release/lib + endif +endif + +MCREZ = $(BUILD_DIR)/bin/mac/release/mcrez + + +XS_DIRECTORIES = \ + $(XS_DIR)/includes \ + $(XS_DIR)/platforms \ + $(XS_DIR)/sources + +XS_HEADERS = \ + $(XS_DIR)/platforms/mac_xs.h \ + $(XS_DIR)/platforms/xsPlatform.h \ + $(XS_DIR)/includes/xs.h \ + $(XS_DIR)/includes/xsmc.h \ + $(XS_DIR)/sources/xsCommon.h \ + $(XS_DIR)/sources/xsAll.h \ + $(XS_DIR)/sources/xsScript.h + +XS_OBJECTS = \ + $(LIB_DIR)/mac_xs.c.o \ + $(LIB_DIR)/xsAll.c.o \ + $(LIB_DIR)/xsAPI.c.o \ + $(LIB_DIR)/xsArguments.c.o \ + $(LIB_DIR)/xsArray.c.o \ + $(LIB_DIR)/xsAtomics.c.o \ + $(LIB_DIR)/xsBigInt.c.o \ + $(LIB_DIR)/xsBoolean.c.o \ + $(LIB_DIR)/xsCode.c.o \ + $(LIB_DIR)/xsCommon.c.o \ + $(LIB_DIR)/xsDataView.c.o \ + $(LIB_DIR)/xsDate.c.o \ + $(LIB_DIR)/xsDebug.c.o \ + $(LIB_DIR)/xsError.c.o \ + $(LIB_DIR)/xsFunction.c.o \ + $(LIB_DIR)/xsGenerator.c.o \ + $(LIB_DIR)/xsGlobal.c.o \ + $(LIB_DIR)/xsJSON.c.o \ + $(LIB_DIR)/xsLexical.c.o \ + $(LIB_DIR)/xsMapSet.c.o \ + $(LIB_DIR)/xsMarshall.c.o \ + $(LIB_DIR)/xsMath.c.o \ + $(LIB_DIR)/xsMemory.c.o \ + $(LIB_DIR)/xsModule.c.o \ + $(LIB_DIR)/xsNumber.c.o \ + $(LIB_DIR)/xsObject.c.o \ + $(LIB_DIR)/xsPlatforms.c.o \ + $(LIB_DIR)/xsProfile.c.o \ + $(LIB_DIR)/xsPromise.c.o \ + $(LIB_DIR)/xsProperty.c.o \ + $(LIB_DIR)/xsProxy.c.o \ + $(LIB_DIR)/xsRegExp.c.o \ + $(LIB_DIR)/xsRun.c.o \ + $(LIB_DIR)/xsScope.c.o \ + $(LIB_DIR)/xsScript.c.o \ + $(LIB_DIR)/xsSourceMap.c.o \ + $(LIB_DIR)/xsString.c.o \ + $(LIB_DIR)/xsSymbol.c.o \ + $(LIB_DIR)/xsSyntaxical.c.o \ + $(LIB_DIR)/xsTree.c.o \ + $(LIB_DIR)/xsType.c.o \ + $(LIB_DIR)/xsdtoa.c.o \ + $(LIB_DIR)/xsmc.c.o \ + $(LIB_DIR)/xsre.c.o + +HEADERS += $(XS_HEADERS) + +C_DEFINES = \ + -DXS_ARCHIVE=1 \ + -DINCLUDE_XSPLATFORM=1 \ + -DXSPLATFORM=\"mac_xs.h\" \ + -DmxRun=1 \ + -DmxParse=1 \ + -DmxNoFunctionLength=1 \ + -DmxNoFunctionName=1 \ + -DmxHostFunctionPrimitive=1 \ + -DmxFewGlobalsTable=1 +ifeq ($(INSTRUMENT),1) + C_DEFINES += -DMODINSTRUMENTATION=1 -DmxInstrument=1 +endif +C_INCLUDES += $(DIRECTORIES) +C_INCLUDES += $(foreach dir,$(XS_DIRECTORIES) $(TMP_DIR),-I$(dir)) +# XS_C_FLAGS = -c -arch i386 +XS_C_FLAGS = -c +ifeq ($(DEBUG),) + XS_C_FLAGS += -D_RELEASE=1 -O3 +else + XS_C_FLAGS += -D_DEBUG=1 -DmxDebug=1 -g -O0 -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter +# C_FLAGS += -DMC_MEMORY_DEBUG=1 +endif +C_FLAGS = $(XS_C_FLAGS) + +LIBRARIES = -framework CoreFoundation + +# LINK_FLAGS = -arch i386 +LINK_FLAGS = + +XSC = $(BUILD_DIR)/bin/mac/debug/xsc +XSID = $(BUILD_DIR)/bin/mac/debug/xsid +XSL = $(BUILD_DIR)/bin/mac/debug/xsl + +VPATH += $(XS_DIRECTORIES) + +.PHONY: all + +all: build + +build: $(LIB_DIR) $(BIN_DIR)/$(NAME) + +clean: + echo "# Clean application" + -rm -rf $(BIN_DIR) + -rm -rf $(TMP_DIR) + +$(LIB_DIR): + mkdir -p $(LIB_DIR) + +$(BIN_DIR)/Info.plist: $(MAIN_DIR)/mac/main.plist + cp -rf $< $@ + echo APPLTINY > $(BIN_DIR)/PkgInfo + +$(BIN_DIR)/$(NAME): $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.c.o $(OBJECTS) + @echo "# cc" $(@F) "($@)" + $(CC) $(LINK_FLAGS) $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.c.o $(OBJECTS) $(LIBRARIES) -o $@ + +$(XS_OBJECTS) : $(XS_HEADERS) +$(LIB_DIR)/%.c.o: %.c + @echo "# cc" $( $(BIN_DIR)/PkgInfo -$(BIN_DIR)/$(NAME): $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.c.o $(OBJECTS) - @echo "# cc" $(@F) "($@)" - $(CC) $(LINK_FLAGS) $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.c.o $(OBJECTS) $(LIBRARIES) -o $@ +$(BIN_DIR)/$(NAME): $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(OBJECTS) + @echo "# cc" $(@F) + $(CC) $(LINK_FLAGS) $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(OBJECTS) $(LIBRARIES) -o $@ $(XS_OBJECTS) : $(XS_HEADERS) $(LIB_DIR)/%.c.o: %.c @@ -162,14 +159,6 @@ $(TMP_DIR)/mc.xs.c.o: $(TMP_DIR)/mc.xs.c $(HEADERS) $(TMP_DIR)/mc.xs.c: $(MODULES) $(MANIFEST) @echo "# xsl modules" $(XSL) -b $(MODULES_DIR) -o $(TMP_DIR) $(PRELOADS) $(CREATION) $(MODULES) - -$(TMP_DIR)/mc.resources.c.o: $(TMP_DIR)/mc.resources.c $(HEADERS) - @echo "# cc" $(. +# + +!IF "$(VERBOSE)"=="1" +!CMDSWITCHES -S +!ELSE +!CMDSWITCHES +S +!ENDIF + +!IF "$(DEBUG)"=="1" +LIB_DIR = $(BUILD_DIR)\tmp\win\debug\lib +!ELSEIF "$(INSTRUMENT)"=="1" +LIB_DIR = $(BUILD_DIR)\tmp\win\instrument\lib +!ELSE +LIB_DIR = $(BUILD_DIR)\tmp\win\release\lib +!ENDIF + +XS_DIRECTORIES = \ + /I$(XS_DIR)\includes \ + /I$(XS_DIR)\platforms \ + /I$(XS_DIR)\sources + +XS_HEADERS = \ + $(XS_DIR)\platforms\win_xs.h \ + $(XS_DIR)\platforms\xsPlatform.h \ + $(XS_DIR)\includes\xs.h \ + $(XS_DIR)\includes\xsmc.h \ + $(XS_DIR)\sources\xsCommon.h \ + $(XS_DIR)\sources\xsAll.h \ + $(XS_DIR)\sources\xsScript.h + +XS_OBJECTS = \ + $(LIB_DIR)\win_xs.o \ + $(LIB_DIR)\xsAll.o \ + $(LIB_DIR)\xsAPI.o \ + $(LIB_DIR)\xsArguments.o \ + $(LIB_DIR)\xsArray.o \ + $(LIB_DIR)\xsAtomics.o \ + $(LIB_DIR)\xsBigInt.o \ + $(LIB_DIR)\xsBoolean.o \ + $(LIB_DIR)\xsCode.o \ + $(LIB_DIR)\xsCommon.o \ + $(LIB_DIR)\xsDataView.o \ + $(LIB_DIR)\xsDate.o \ + $(LIB_DIR)\xsDebug.o \ + $(LIB_DIR)\xsError.o \ + $(LIB_DIR)\xsFunction.o \ + $(LIB_DIR)\xsGenerator.o \ + $(LIB_DIR)\xsGlobal.o \ + $(LIB_DIR)\xsJSON.o \ + $(LIB_DIR)\xsLexical.o \ + $(LIB_DIR)\xsMapSet.o \ + $(LIB_DIR)\xsMarshall.o \ + $(LIB_DIR)\xsMath.o \ + $(LIB_DIR)\xsMemory.o \ + $(LIB_DIR)\xsModule.o \ + $(LIB_DIR)\xsNumber.o \ + $(LIB_DIR)\xsObject.o \ + $(LIB_DIR)\xsPlatforms.o \ + $(LIB_DIR)\xsProfile.o \ + $(LIB_DIR)\xsPromise.o \ + $(LIB_DIR)\xsProperty.o \ + $(LIB_DIR)\xsProxy.o \ + $(LIB_DIR)\xsRegExp.o \ + $(LIB_DIR)\xsRun.o \ + $(LIB_DIR)\xsScope.o \ + $(LIB_DIR)\xsScript.o \ + $(LIB_DIR)\xsSourceMap.o \ + $(LIB_DIR)\xsString.o \ + $(LIB_DIR)\xsSymbol.o \ + $(LIB_DIR)\xsSyntaxical.o \ + $(LIB_DIR)\xsTree.o \ + $(LIB_DIR)\xsType.o \ + $(LIB_DIR)\xsdtoa.o \ + $(LIB_DIR)\xsmc.o \ + $(LIB_DIR)\xsre.o + +DIRECTORIES = $(DIRECTORIES) $(XS_DIRECTORIES) + +HEADERS = $(HEADERS) $(XS_HEADERS) + +C_DEFINES = \ + /D XS_ARCHIVE=1 \ + /D INCLUDE_XSPLATFORM=1 \ + /D XSPLATFORM=\"win_xs.h\" \ + /D mxRun=1 \ + /D mxParse=1 \ + /D mxNoFunctionLength=1 \ + /D mxNoFunctionName=1 \ + /D mxHostFunctionPrimitive=1 \ + /D mxFewGlobalsTable=1 +!IF "$(INSTRUMENT)"=="1" +C_DEFINES = $(C_DEFINES) \ + /D MODINSTRUMENTATION=1 \ + /D mxInstrument=1 +!ENDIF + +C_INCLUDES = $(DIRECTORIES) /I$(TMP_DIR) + +XS_C_FLAGS = \ + /c \ + /D _CONSOLE \ + /D WIN32 \ + /D _CRT_SECURE_NO_DEPRECATE \ + /D HAVE_MEMMOVE=1 \ + /nologo +!IF "$(DEBUG)"=="1" +XS_C_FLAGS = $(XS_C_FLAGS) \ + /D _DEBUG \ + /D mxDebug=1 \ + /Fp$(TMP_DIR)\ \ + /Od \ + /W3 \ + /Z7 +!ELSE +XS_C_FLAGS = $(XS_C_FLAGS) \ + /D NDEBUG \ + /Fp$(TMP_DIR)\ \ + /O2 \ + /W0 +!ENDIF +C_FLAGS = $(XS_C_FLAGS) + +RC_OPTIONS = /nologo + +LINK_LIBRARIES = ws2_32.lib advapi32.lib comctl32.lib comdlg32.lib gdi32.lib kernel32.lib user32.lib Iphlpapi.lib wlanapi.lib + +LINK_OPTIONS = /incremental:no /machine:I386 /nologo /subsystem:console +!IF "$(DEBUG)"=="1" +LINK_OPTIONS = $(LINK_OPTIONS) /debug +!ENDIF + +MCLOCAL = $(BUILD_DIR)/bin/mac/debug/mclocal +MCREZ = $(BUILD_DIR)\bin\win\debug\mcrez +XSC = $(BUILD_DIR)\bin\win\debug\xsc +XSID = $(BUILD_DIR)\bin\win\debug\xsid +XSL = $(BUILD_DIR)\bin\win\debug\xsl + +all: build + +build: $(LIB_DIR) $(BIN_DIR)\$(NAME).exe + +clean: + echo # Clean project lib bin and tmp + echo $(BIN_DIR) + del /s/q/f $(BIN_DIR)\*.* > NULL + rmdir /s/q $(BIN_DIR) + echo $(TMP_DIR) + del /s/q/f $(TMP_DIR)\*.* > NULL + rmdir /s/q $(TMP_DIR) + echo $(LIB_DIR) + if exist $(LIB_DIR) del /s/q/f $(LIB_DIR)\*.* > NULL + if exist $(LIB_DIR) rmdir /s/q $(LIB_DIR) + + +$(LIB_DIR) : + if not exist $(LIB_DIR)\$(NULL) mkdir $(LIB_DIR) + +$(BIN_DIR)\$(NAME).exe: $(XS_OBJECTS) $(TMP_DIR)\mc.xs.o $(TMP_DIR)\mc.resources.o $(OBJECTS) + @echo # link $(NAME).exe ($(BIN_DIR)\$(NAME)) + link $(LINK_OPTIONS) $(LINK_LIBRARIES) $(XS_OBJECTS) $(TMP_DIR)\mc.xs.o $(TMP_DIR)\mc.resources.o $(OBJECTS) /implib:$(TMP_DIR)\$(NAME).lib /out:$@ + +$(XS_OBJECTS) : $(XS_HEADERS) +{$(XS_DIR)\sources\}.c{$(LIB_DIR)\}.o: + cl $(C_DEFINES) $(C_INCLUDES) $(XS_C_FLAGS) $< /Fo$@ +{$(XS_DIR)\platforms\}.c{$(LIB_DIR)\}.o: + cl $(C_DEFINES) $(C_INCLUDES) $(XS_C_FLAGS) $< /Fo$@ + +$(TMP_DIR)\mc.xs.o: $(TMP_DIR)\mc.xs.c $(HEADERS) + cl $(C_DEFINES) $(C_INCLUDES) $(XS_C_FLAGS) $(TMP_DIR)\mc.xs.c /Fo$@ + +$(TMP_DIR)\mc.xs.c: $(MODULES) $(MANIFEST) + @echo # xsl modules + $(XSL) -b $(MODULES_DIR) -o $(TMP_DIR) $(PRELOADS) $(CREATION) $(MODULES) + + +$(TMP_DIR)\mc.resources.o: $(TMP_DIR)\mc.resources.c $(HEADERS) + cl $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) $(TMP_DIR)\mc.resources.c /Fo$@ + +$(TMP_DIR)\mc.resources.c: $(DATA) $(RESOURCES) $(MANIFEST) + @echo # mcrez resources + $(MCREZ) < Date: Mon, 28 Dec 2020 14:32:15 -0400 Subject: [PATCH 21/32] Fixed delay on machine start when debugger not connected --- xs/sources/xsDebug.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xs/sources/xsDebug.c b/xs/sources/xsDebug.c index 9013b963a3..222d0b8d65 100644 --- a/xs/sources/xsDebug.c +++ b/xs/sources/xsDebug.c @@ -155,6 +155,7 @@ enum { }; static const char gxHexaDigits[] ICACHE_FLASH_ATTR = "0123456789ABCDEF"; +bool _debugLoginAttempted = false; // true once we have attempted fxLogin, to avoid connection delay when instantiating multiple machines (such as Workers) without a debugger void fxCheck(txMachine* the, txString thePath, txInteger theLine) { @@ -1794,7 +1795,10 @@ txBoolean fxIsModuleAvailable(txMachine* the, txSlot* realm, txSlot* module) void fxLogin(txMachine* the) { if (!fxIsConnected(the)) { + if (_debugLoginAttempted) + return; fxConnect(the); + _debugLoginAttempted = TRUE; if (!fxIsConnected(the)) return; } From dc31dfcc887aa1334b9d2c942fb0a923198442ff Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 28 Dec 2020 14:33:08 -0400 Subject: [PATCH 22/32] Improved message handling when loop is being starved --- contributed/cli/cli-win/main.c | 35 ++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/contributed/cli/cli-win/main.c b/contributed/cli/cli-win/main.c index 0594e1fea1..a9a2314ecf 100644 --- a/contributed/cli/cli-win/main.c +++ b/contributed/cli/cli-win/main.c @@ -32,14 +32,18 @@ #include #include "cli.h" #include "sysinfoapi.h" +#include "screen.h" + +extern txScreen screen; unsigned int messagePumpThreadId = 0; // thread ID of the thread running the windows message pump #ifdef mxInstrument +#define INSTRUMENTATION_FREQUENCY 1000 // frequency of instrumentation updates in ms #define WM_APP_INSTRUMENTATION (WM_APP + 1) // ID of our private instrumentation message static VOID CALLBACK sendInstrumentationMessage(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - PostThreadMessage(messagePumpThreadId, WM_APP_INSTRUMENTATION, 0, 0); + PostMessage(((txMachine *) screen.machine)->window, WM_APP_INSTRUMENTATION, 0, 0); } #endif @@ -96,20 +100,20 @@ void messagePump(char *pathToMod) { // set up a timer for the instrumentation #ifdef mxInstrument - SetTimer(NULL, 1, 1000, sendInstrumentationMessage); + SetTimer(((txMachine *) screen.machine)->window, 1, INSTRUMENTATION_FREQUENCY, sendInstrumentationMessage); #endif // process the windows message loop until terminated - while( GetMessage(&msg, NULL, 0, 0) > 0 ) { + while( GetMessage(&msg, ((txMachine *) screen.machine)->window, 0, 0) > 0 ) { #ifdef mxInstrument if (msg.message == WM_APP_INSTRUMENTATION) { - // make sure we don't issue instrumentation more often than once/second - if the host gets busy, a - // bunch of messages can be queued up, and this drops the extra ones on the floor + // make sure we don't issue instrumentation more often than once/INSTRUMENTATION_FREQUENCY - if + // the host gets busy, a bunch of messages can be queued up, and this drops the extra ones on the floor static DWORD instrumentTime = 0; DWORD currentTime = GetTickCount(); if (instrumentTime < currentTime) { - instrumentTime = currentTime + 1000; + instrumentTime = currentTime + INSTRUMENTATION_FREQUENCY; instrumentMachine(); } @@ -118,12 +122,27 @@ void messagePump(char *pathToMod) { #endif // do we need to shut down? - if (msg.message == WM_CLOSE) + if (msg.message == WM_CLOSE) { break; + } // go ahead and let the message get dispatched TranslateMessage(&msg); DispatchMessage(&msg); + + // if the running operation never stops sending messages (this can happen such as with workers that + // create workers on every loop), the timer gets starved because Windows does not process timer + // events unless the queue is empty. This will ensure that timers continue to operate even + // when the loop is busy + while (PeekMessage(&msg, ((txMachine *) screen.machine)->window, WM_TIMER, WM_TIMER, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // similar problem as WM_TIMER for the WM_CLOSE message - it does get processed eventually, but to + // speed it up we check here + if (PeekMessage(&msg, ((txMachine *) screen.machine)->window, WM_CLOSE, WM_CLOSE, PM_REMOVE)) + break; } // done - end our XS machine @@ -139,7 +158,7 @@ BOOL WINAPI ctrlHandler(_In_ DWORD dwCtrlType) { { case CTRL_C_EVENT: fprintf(stderr, "\nShutting down\n"); - PostThreadMessage(messagePumpThreadId, WM_CLOSE, 0, 0); + PostMessage(((txMachine *) screen.machine)->window, WM_CLOSE, 0, 0); return TRUE; default: From 4c815c700dc9cc6e69b6d3472d9513d962276bfe Mon Sep 17 00:00:00 2001 From: Chris Midgley Date: Mon, 28 Dec 2020 10:43:44 -0800 Subject: [PATCH 23/32] Fixed for compile-time portability --- xs/sources/xsDebug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xs/sources/xsDebug.c b/xs/sources/xsDebug.c index 222d0b8d65..7d84c124a6 100644 --- a/xs/sources/xsDebug.c +++ b/xs/sources/xsDebug.c @@ -155,7 +155,7 @@ enum { }; static const char gxHexaDigits[] ICACHE_FLASH_ATTR = "0123456789ABCDEF"; -bool _debugLoginAttempted = false; // true once we have attempted fxLogin, to avoid connection delay when instantiating multiple machines (such as Workers) without a debugger +txBoolean _debugLoginAttempted = 0; // true once we have attempted fxLogin, to avoid connection delay when instantiating multiple machines (such as Workers) without a debugger void fxCheck(txMachine* the, txString thePath, txInteger theLine) { @@ -1798,7 +1798,7 @@ void fxLogin(txMachine* the) if (_debugLoginAttempted) return; fxConnect(the); - _debugLoginAttempted = TRUE; + _debugLoginAttempted = 1; if (!fxIsConnected(the)) return; } From 8393fe264e818cc8b8a786748d52f8dfc7e15079 Mon Sep 17 00:00:00 2001 From: Chris Midgley Date: Mon, 28 Dec 2020 14:52:57 -0400 Subject: [PATCH 24/32] Fixed issue with compilation without debug --- contributed/cli/cli.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contributed/cli/cli.c b/contributed/cli/cli.c index 086e5d4db5..ba8af64214 100644 --- a/contributed/cli/cli.c +++ b/contributed/cli/cli.c @@ -99,7 +99,9 @@ int startMachine(char *archivePath) { } // instruct the machine to call us prior to entering the debugger, so we can update instrumentation +#ifdef mxDebug machine->onBreak = debugBreak; +#endif // link our screen and machine objects together screen.machine = (void *) machine; From 08d0f11623749ef5664209829bc0ae9c3929396c Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 28 Dec 2020 15:21:09 -0400 Subject: [PATCH 25/32] Cleanup prior to pull request --- contributed/cli/screen.h | 31 --- modules/files/file/lin/modFile.c | 317 ------------------------------- 2 files changed, 348 deletions(-) delete mode 100644 modules/files/file/lin/modFile.c diff --git a/contributed/cli/screen.h b/contributed/cli/screen.h index 181a6206e6..ee3c1b4b6e 100644 --- a/contributed/cli/screen.h +++ b/contributed/cli/screen.h @@ -78,35 +78,4 @@ struct sxScreen { void *firstWorker; txMutex workersMutex; txThread mainThread; - - - - // void* view; - // void* archive; - // txScreenAbortProc abort; - // txScreenBufferChangedProc bufferChanged; - // txScreenFormatChangedProc formatChanged; - // txScreenIdleProc idle; - // txScreenMessageProc invoke; - // txScreenKeyProc key; - // txScreenMessageProc post; - // txScreenQuitProc quit; - // txScreenStartProc start; - // txScreenStopProc stop; - // txScreenTouchProc touch; - // int flags; - // long instrumentTime; - // int pixelFormat; - // int rotation; - // int width; - // int height; - // uint16_t *clut; - // uint8_t palette[16 * screenBytesPerPixel]; - // void *frameBuffer; // only used when kPocoFrameBuffer - // uint32_t frameBufferLength; // only used when kPocoFrameBuffer - // unsigned char *rowAddress; - // int rowCount; - // int rowDelta; - // int rowIndex; - // unsigned char buffer[1]; }; \ No newline at end of file diff --git a/modules/files/file/lin/modFile.c b/modules/files/file/lin/modFile.c deleted file mode 100644 index b43fdcd020..0000000000 --- a/modules/files/file/lin/modFile.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright (c) 2016-2020 Moddable Tech, Inc. - * - * This file is part of the Moddable SDK Runtime. - * - * The Moddable SDK Runtime is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Moddable SDK Runtime is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the Moddable SDK Runtime. If not, see . - * - */ - -#include "xsmc.h" -#include "modInstrumentation.h" -#include "mc.xs.h" // for xsID_ values - -#include -#include -#include -#include -#include -#include -#include - -typedef struct { - DIR *dir; - int rootPathLen; - char path[1]; -} iteratorRecord, *iter; - -static FILE *getFile(xsMachine *the) -{ - FILE *result = xsmcGetHostData(xsThis); - if (!result) - xsUnknownError("closed"); - return result; -} - -void xs_file_destructor(void *data) -{ - if (data) { - fclose((FILE *)data); - - modInstrumentationAdjust(Files, -1); - } -} - -void xs_File(xsMachine *the) -{ - int argc = xsmcArgc; - FILE *file; - char *path; - uint8_t write = (argc < 2) ? 0 : xsmcToBoolean(xsArg(1)); - - path = xsmcToString(xsArg(0)); - file = fopen(path, write ? "rb+" : "rb"); - if (NULL == file) { - if (write) - file = fopen(path, "wb+"); - if (NULL == file) - xsUnknownError("file not found"); - } - xsmcSetHostData(xsThis, (void *)((uintptr_t)file)); - - modInstrumentationAdjust(Files, +1); -} - -void xs_file_read(xsMachine *the) -{ - FILE *file = getFile(the); - int32_t result; - int argc = xsmcArgc; - int dstLen = (argc < 2) ? -1 : xsmcToInteger(xsArg(1)); - void *dst; - xsSlot *s1, *s2; - struct stat buf; - int32_t position = ftell(file); - - fstat(fileno(file), &buf); - if ((-1 == dstLen) || (buf.st_size < (position + dstLen))) { - if (position >= buf.st_size) - xsUnknownError("read past end of file"); - dstLen = buf.st_size - position; - } - - s1 = &xsArg(0); - - xsmcVars(1); - xsmcGet(xsVar(0), xsGlobal, xsID_String); - s2 = &xsVar(0); - if (s1->data[2] == s2->data[2]) { - xsResult = xsStringBuffer(NULL, dstLen); - dst = xsmcToString(xsResult); - } - else { - xsmcSetArrayBuffer(xsResult, NULL, dstLen); - dst = xsmcToArrayBuffer(xsResult); - } - - result = fread(dst, 1, dstLen, file); - if (result != dstLen) - xsUnknownError("file read failed"); -} - -void xs_file_write(xsMachine *the) -{ - FILE *file = getFile(the); - int32_t result; - int argc = xsmcArgc, i; - - for (i = 0; i < argc; i++) { - uint8_t *src; - int32_t srcLen; - int type = xsmcTypeOf(xsArg(i)); - uint8_t temp; - - if (xsStringType == type) { - src = (uint8_t*)xsmcToString(xsArg(i)); - srcLen = c_strlen((const char *)src); - } - else if ((xsIntegerType == type) || (xsNumberType == type)) { - temp = (uint8_t)xsmcToInteger(xsArg(i)); - src = &temp; - srcLen = 1; - } - else { - src = xsmcToArrayBuffer(xsArg(i)); - srcLen = xsmcGetArrayBufferLength(xsArg(i)); - } - - result = fwrite(src, 1, srcLen, file); - if (result != srcLen) - xsUnknownError("file write failed"); - } - result = fflush(file); - if (0 != result) - xsUnknownError("file flush failed"); -} - -void xs_file_close(xsMachine *the) -{ - FILE *file = getFile(the); - xs_file_destructor((void *)((uintptr_t)file)); - xsmcSetHostData(xsThis, (void *)NULL); -} - -void xs_file_get_length(xsMachine *the) -{ - FILE *file = getFile(the); - struct stat buf; - - fstat(fileno(file), &buf); - xsResult = xsInteger(buf.st_size); -} - -void xs_file_get_position(xsMachine *the) -{ - FILE *file = getFile(the); - int32_t position = ftell(file); - xsResult = xsInteger(position); -} - -void xs_file_set_position(xsMachine *the) -{ - FILE *file = getFile(the); - int32_t position = xsmcToInteger(xsArg(0)); - fseek(file, position, SEEK_SET); -} - -void xs_file_delete(xsMachine *the) -{ - int32_t result; - char *path = xsmcToString(xsArg(0)); - - result = unlink(path); - - xsResult = xsBoolean(result == 0); -} - -void xs_file_exists(xsMachine *the) -{ - struct stat buf; - int32_t result; - char *path = xsmcToString(xsArg(0)); - - result = stat(path, &buf); - - xsResult = xsBoolean(result == 0); -} - -void xs_file_rename(xsMachine *the) -{ - char* path; - char toPath[PATH_MAX + 1]; - int32_t result; - char* slash; - size_t pathLength = 0; - - path = xsmcToString(xsArg(0)); - slash = c_strrchr(path, '/'); - if (slash){ - pathLength = slash - path + 1; - if (pathLength >= sizeof(toPath)) xsUnknownError("path is too long"); - c_memcpy(toPath, path, pathLength); - toPath[pathLength] = '\0'; - } - - xsmcToStringBuffer(xsArg(1), toPath + pathLength, sizeof(toPath) - pathLength); - path = xsmcToString(xsArg(0)); - - result = rename(path, toPath); - xsResult = xsBoolean(result == 0); -} - -void xs_directory_create(xsMachine *the) -{ - char *path = xsmcToString(xsArg(0)); - int result = mkdir(path, 0755); - if (result && (EEXIST != errno)) - xsUnknownError("failed"); -} - -void xs_directory_delete(xsMachine *the) -{ - char *path = xsmcToString(xsArg(0)); - int result = rmdir(path); - if (result && (ENOENT != errno)) - xsUnknownError("failed"); -} - -void xs_file_iterator_destructor(void *data) -{ - iter d = data; - - if (d) { - if (d->dir) - closedir(d->dir); - free(d); - modInstrumentationAdjust(Files, -1); - } -} - -void xs_File_Iterator(xsMachine *the) -{ - iter d; - int i; - char *p; - - p = xsmcToString(xsArg(0)); - i = c_strlen(p); - if (i == 0) - xsUnknownError("bad path"); - d = c_calloc(1, sizeof(iteratorRecord) + i + 2 + PATH_MAX + 1); - c_strcpy(d->path, p); - if (p[i - 1] != '/') - d->path[i++] = '/'; - d->rootPathLen = i; - - if (NULL == (d->dir = opendir(d->path))) { - c_free(d); - xsUnknownError("failed to open directory"); - } - xsmcSetHostData(xsThis, d); - - modInstrumentationAdjust(Files, +1); -} - -void xs_file_iterator_next(xsMachine *the) -{ - iter d = xsmcGetHostData(xsThis); - struct dirent *de; - struct stat buf; - - if (!d || !d->dir) return; - - do { - if (NULL == (de = readdir(d->dir))) { - xs_file_iterator_destructor(d); - xsmcSetHostData(xsThis, NULL); - return; - } - } while ((DT_DIR != de->d_type) && (DT_REG != de->d_type)); - - xsResult = xsmcNewObject(); - xsmcVars(1); - xsmcSetString(xsVar(0), de->d_name); - xsmcSet(xsResult, xsID_name, xsVar(0)); - - if (DT_REG == de->d_type) { - c_strcpy(d->path + d->rootPathLen, de->d_name); - if (-1 == stat(d->path, &buf)) - xsUnknownError("stat error"); - xsmcSetInteger(xsVar(0), buf.st_size); - xsmcSet(xsResult, xsID_length, xsVar(0)); - } -} - -void xs_file_system_config(xsMachine *the) -{ - xsResult = xsmcNewObject(); - xsmcVars(1); - xsmcSetInteger(xsVar(0), PATH_MAX); - xsmcSet(xsResult, xsID_maxPathLength, xsVar(0)); -} - -void xs_file_system_info(xsMachine *the) -{ - xsResult = xsmcNewObject(); -} From 304dc742ffd49fc86513bb23bcfb73b037fdc47a Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 28 Dec 2020 16:24:42 -0400 Subject: [PATCH 26/32] Removed fake linux preference file --- modules/files/preference/lin/modPreference.c | 63 -------------------- 1 file changed, 63 deletions(-) delete mode 100644 modules/files/preference/lin/modPreference.c diff --git a/modules/files/preference/lin/modPreference.c b/modules/files/preference/lin/modPreference.c deleted file mode 100644 index ec2b918d49..0000000000 --- a/modules/files/preference/lin/modPreference.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2016-2018 Moddable Tech, Inc. - * - * This file is part of the Moddable SDK Runtime. - * - * The Moddable SDK Runtime is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Moddable SDK Runtime is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the Moddable SDK Runtime. If not, see . - * - */ - -#include "xsmc.h" -#include "xsHost.h" -#include "mc.xs.h" // for xsID_ values - -#define kPreferencesMagic 0x81213141 - -enum { - kPrefsTypeBoolean = 1, - kPrefsTypeInteger = 2, - kPrefsTypeString = 3, - kPrefsTypeBuffer = 4, -}; - -#define kBufferSize (64) - -static void resetPrefs(void); -static uint8_t findPrefsBlock(uint32_t *offset); -static uint8_t findPrefOffset(const char *domain, const char *key, uint32_t *entryOffset, uint32_t *valueOffset, uint32_t *entrySize, uint8_t *buffer); -static int getPrefSize(const uint8_t *pref); -static uint8_t erasePref(const char *domain, const char *key, uint8_t *buffer); -static uint8_t setPref(xsMachine *the, char *domain, char *name, uint8_t type, uint8_t *value, uint16_t byteCount); - -void xs_preference_set(xsMachine *the) -{ - xsUnknownError("can't save prefs"); -} - -void xs_preference_get(xsMachine *the) -{ -} - -void xs_preference_delete(xsMachine *the) -{ -} - -void xs_preference_keys(xsMachine *the) -{ -} - -void xs_preference_reset(xsMachine *the) -{ -} - From 13c7b0b3dae5212954f812d1a56d8fef19640b37 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 28 Dec 2020 21:26:39 -0400 Subject: [PATCH 27/32] Put back linux file module --- modules/files/file/lin/modFile.c | 317 +++++++++++++++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 modules/files/file/lin/modFile.c diff --git a/modules/files/file/lin/modFile.c b/modules/files/file/lin/modFile.c new file mode 100644 index 0000000000..b43fdcd020 --- /dev/null +++ b/modules/files/file/lin/modFile.c @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2016-2020 Moddable Tech, Inc. + * + * This file is part of the Moddable SDK Runtime. + * + * The Moddable SDK Runtime is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Runtime is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the Moddable SDK Runtime. If not, see . + * + */ + +#include "xsmc.h" +#include "modInstrumentation.h" +#include "mc.xs.h" // for xsID_ values + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + DIR *dir; + int rootPathLen; + char path[1]; +} iteratorRecord, *iter; + +static FILE *getFile(xsMachine *the) +{ + FILE *result = xsmcGetHostData(xsThis); + if (!result) + xsUnknownError("closed"); + return result; +} + +void xs_file_destructor(void *data) +{ + if (data) { + fclose((FILE *)data); + + modInstrumentationAdjust(Files, -1); + } +} + +void xs_File(xsMachine *the) +{ + int argc = xsmcArgc; + FILE *file; + char *path; + uint8_t write = (argc < 2) ? 0 : xsmcToBoolean(xsArg(1)); + + path = xsmcToString(xsArg(0)); + file = fopen(path, write ? "rb+" : "rb"); + if (NULL == file) { + if (write) + file = fopen(path, "wb+"); + if (NULL == file) + xsUnknownError("file not found"); + } + xsmcSetHostData(xsThis, (void *)((uintptr_t)file)); + + modInstrumentationAdjust(Files, +1); +} + +void xs_file_read(xsMachine *the) +{ + FILE *file = getFile(the); + int32_t result; + int argc = xsmcArgc; + int dstLen = (argc < 2) ? -1 : xsmcToInteger(xsArg(1)); + void *dst; + xsSlot *s1, *s2; + struct stat buf; + int32_t position = ftell(file); + + fstat(fileno(file), &buf); + if ((-1 == dstLen) || (buf.st_size < (position + dstLen))) { + if (position >= buf.st_size) + xsUnknownError("read past end of file"); + dstLen = buf.st_size - position; + } + + s1 = &xsArg(0); + + xsmcVars(1); + xsmcGet(xsVar(0), xsGlobal, xsID_String); + s2 = &xsVar(0); + if (s1->data[2] == s2->data[2]) { + xsResult = xsStringBuffer(NULL, dstLen); + dst = xsmcToString(xsResult); + } + else { + xsmcSetArrayBuffer(xsResult, NULL, dstLen); + dst = xsmcToArrayBuffer(xsResult); + } + + result = fread(dst, 1, dstLen, file); + if (result != dstLen) + xsUnknownError("file read failed"); +} + +void xs_file_write(xsMachine *the) +{ + FILE *file = getFile(the); + int32_t result; + int argc = xsmcArgc, i; + + for (i = 0; i < argc; i++) { + uint8_t *src; + int32_t srcLen; + int type = xsmcTypeOf(xsArg(i)); + uint8_t temp; + + if (xsStringType == type) { + src = (uint8_t*)xsmcToString(xsArg(i)); + srcLen = c_strlen((const char *)src); + } + else if ((xsIntegerType == type) || (xsNumberType == type)) { + temp = (uint8_t)xsmcToInteger(xsArg(i)); + src = &temp; + srcLen = 1; + } + else { + src = xsmcToArrayBuffer(xsArg(i)); + srcLen = xsmcGetArrayBufferLength(xsArg(i)); + } + + result = fwrite(src, 1, srcLen, file); + if (result != srcLen) + xsUnknownError("file write failed"); + } + result = fflush(file); + if (0 != result) + xsUnknownError("file flush failed"); +} + +void xs_file_close(xsMachine *the) +{ + FILE *file = getFile(the); + xs_file_destructor((void *)((uintptr_t)file)); + xsmcSetHostData(xsThis, (void *)NULL); +} + +void xs_file_get_length(xsMachine *the) +{ + FILE *file = getFile(the); + struct stat buf; + + fstat(fileno(file), &buf); + xsResult = xsInteger(buf.st_size); +} + +void xs_file_get_position(xsMachine *the) +{ + FILE *file = getFile(the); + int32_t position = ftell(file); + xsResult = xsInteger(position); +} + +void xs_file_set_position(xsMachine *the) +{ + FILE *file = getFile(the); + int32_t position = xsmcToInteger(xsArg(0)); + fseek(file, position, SEEK_SET); +} + +void xs_file_delete(xsMachine *the) +{ + int32_t result; + char *path = xsmcToString(xsArg(0)); + + result = unlink(path); + + xsResult = xsBoolean(result == 0); +} + +void xs_file_exists(xsMachine *the) +{ + struct stat buf; + int32_t result; + char *path = xsmcToString(xsArg(0)); + + result = stat(path, &buf); + + xsResult = xsBoolean(result == 0); +} + +void xs_file_rename(xsMachine *the) +{ + char* path; + char toPath[PATH_MAX + 1]; + int32_t result; + char* slash; + size_t pathLength = 0; + + path = xsmcToString(xsArg(0)); + slash = c_strrchr(path, '/'); + if (slash){ + pathLength = slash - path + 1; + if (pathLength >= sizeof(toPath)) xsUnknownError("path is too long"); + c_memcpy(toPath, path, pathLength); + toPath[pathLength] = '\0'; + } + + xsmcToStringBuffer(xsArg(1), toPath + pathLength, sizeof(toPath) - pathLength); + path = xsmcToString(xsArg(0)); + + result = rename(path, toPath); + xsResult = xsBoolean(result == 0); +} + +void xs_directory_create(xsMachine *the) +{ + char *path = xsmcToString(xsArg(0)); + int result = mkdir(path, 0755); + if (result && (EEXIST != errno)) + xsUnknownError("failed"); +} + +void xs_directory_delete(xsMachine *the) +{ + char *path = xsmcToString(xsArg(0)); + int result = rmdir(path); + if (result && (ENOENT != errno)) + xsUnknownError("failed"); +} + +void xs_file_iterator_destructor(void *data) +{ + iter d = data; + + if (d) { + if (d->dir) + closedir(d->dir); + free(d); + modInstrumentationAdjust(Files, -1); + } +} + +void xs_File_Iterator(xsMachine *the) +{ + iter d; + int i; + char *p; + + p = xsmcToString(xsArg(0)); + i = c_strlen(p); + if (i == 0) + xsUnknownError("bad path"); + d = c_calloc(1, sizeof(iteratorRecord) + i + 2 + PATH_MAX + 1); + c_strcpy(d->path, p); + if (p[i - 1] != '/') + d->path[i++] = '/'; + d->rootPathLen = i; + + if (NULL == (d->dir = opendir(d->path))) { + c_free(d); + xsUnknownError("failed to open directory"); + } + xsmcSetHostData(xsThis, d); + + modInstrumentationAdjust(Files, +1); +} + +void xs_file_iterator_next(xsMachine *the) +{ + iter d = xsmcGetHostData(xsThis); + struct dirent *de; + struct stat buf; + + if (!d || !d->dir) return; + + do { + if (NULL == (de = readdir(d->dir))) { + xs_file_iterator_destructor(d); + xsmcSetHostData(xsThis, NULL); + return; + } + } while ((DT_DIR != de->d_type) && (DT_REG != de->d_type)); + + xsResult = xsmcNewObject(); + xsmcVars(1); + xsmcSetString(xsVar(0), de->d_name); + xsmcSet(xsResult, xsID_name, xsVar(0)); + + if (DT_REG == de->d_type) { + c_strcpy(d->path + d->rootPathLen, de->d_name); + if (-1 == stat(d->path, &buf)) + xsUnknownError("stat error"); + xsmcSetInteger(xsVar(0), buf.st_size); + xsmcSet(xsResult, xsID_length, xsVar(0)); + } +} + +void xs_file_system_config(xsMachine *the) +{ + xsResult = xsmcNewObject(); + xsmcVars(1); + xsmcSetInteger(xsVar(0), PATH_MAX); + xsmcSet(xsResult, xsID_maxPathLength, xsVar(0)); +} + +void xs_file_system_info(xsMachine *the) +{ + xsResult = xsmcNewObject(); +} From 2b977a6c75e1d2e5ef9f3b82a83a068f6b68bb29 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 31 Dec 2020 13:12:13 -0400 Subject: [PATCH 28/32] Added launching and xsbug support; fixed clean --- tools/mcconfig/nmake.cli-win.mk | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tools/mcconfig/nmake.cli-win.mk b/tools/mcconfig/nmake.cli-win.mk index 89b82e0870..4bf6a10906 100644 --- a/tools/mcconfig/nmake.cli-win.mk +++ b/tools/mcconfig/nmake.cli-win.mk @@ -152,28 +152,27 @@ XSC = $(BUILD_DIR)\bin\win\debug\xsc XSID = $(BUILD_DIR)\bin\win\debug\xsid XSL = $(BUILD_DIR)\bin\win\debug\xsl -all: build +all: $(LIB_DIR) $(BIN_DIR)\$(NAME).exe +!IF "$(DEBUG)"=="1" + start xsbug +!ENDIF + $(BIN_DIR)\$(NAME).exe build: $(LIB_DIR) $(BIN_DIR)\$(NAME).exe + echo # Project built; executable is: + echo $(BIN_DIR)\$(NAME) clean: - echo # Clean project lib bin and tmp - echo $(BIN_DIR) - del /s/q/f $(BIN_DIR)\*.* > NULL - rmdir /s/q $(BIN_DIR) + echo # Clean project echo $(TMP_DIR) del /s/q/f $(TMP_DIR)\*.* > NULL rmdir /s/q $(TMP_DIR) - echo $(LIB_DIR) - if exist $(LIB_DIR) del /s/q/f $(LIB_DIR)\*.* > NULL - if exist $(LIB_DIR) rmdir /s/q $(LIB_DIR) - $(LIB_DIR) : if not exist $(LIB_DIR)\$(NULL) mkdir $(LIB_DIR) $(BIN_DIR)\$(NAME).exe: $(XS_OBJECTS) $(TMP_DIR)\mc.xs.o $(TMP_DIR)\mc.resources.o $(OBJECTS) - @echo # link $(NAME).exe ($(BIN_DIR)\$(NAME)) + @echo # link $(NAME).exe link $(LINK_OPTIONS) $(LINK_LIBRARIES) $(XS_OBJECTS) $(TMP_DIR)\mc.xs.o $(TMP_DIR)\mc.resources.o $(OBJECTS) /implib:$(TMP_DIR)\$(NAME).lib /out:$@ $(XS_OBJECTS) : $(XS_HEADERS) From c64aca25914e47342969e82decb25c1cc3914cfa Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 31 Dec 2020 17:05:08 -0400 Subject: [PATCH 29/32] Cleaned up mac/lin make (xsbug, launch) --- tools/mcconfig/make.cli-lin.mk | 19 +++++++++++++++---- tools/mcconfig/make.cli-mac.mk | 19 ++++++++++++++----- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/tools/mcconfig/make.cli-lin.mk b/tools/mcconfig/make.cli-lin.mk index 0fa5d821e6..0a87a5e66a 100644 --- a/tools/mcconfig/make.cli-lin.mk +++ b/tools/mcconfig/make.cli-lin.mk @@ -140,20 +140,31 @@ VPATH += $(XS_DIRECTORIES) .PHONY: all -all: build +all: preamble +ifeq ($(DEBUG),1) + @echo "# starting xsbug" + $(shell nohup "$(BUILD_DIR)/bin/lin/release/xsbug" > /dev/null 2>&1 &) +endif + sleep 1 + "$(BIN_DIR)/$(NAME)" + +build: preamble + @echo "# Project built; executable is:" + @echo "$(BIN_DIR)/$(NAME)" -build: $(LIB_DIR) $(BIN_DIR)/$(NAME) +preamble: $(LIB_DIR) $(BIN_DIR)/$(NAME) + @echo "# preamble done" $(LIB_DIR): mkdir -p $(LIB_DIR) $(BIN_DIR)/$(NAME): $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.c.o $(OBJECTS) - @echo "# ld " $(/dev/null -rm -rf $(TMP_DIR) 2>/dev/null $(XS_OBJECTS) : $(XS_HEADERS) diff --git a/tools/mcconfig/make.cli-mac.mk b/tools/mcconfig/make.cli-mac.mk index 3c482be282..5b4a56b0c1 100644 --- a/tools/mcconfig/make.cli-mac.mk +++ b/tools/mcconfig/make.cli-mac.mk @@ -130,13 +130,22 @@ VPATH += $(XS_DIRECTORIES) .PHONY: all -all: build +all: preamble +ifeq ($(DEBUG),1) + $(shell pkill serial2xsbug) + open -a "$(BUILD_DIR)/bin/mac/release/xsbug.app" -g +endif + @echo "# starting app" + "$(BIN_DIR)/$(NAME)" + +build: preamble + @echo "# Project built; executable is:" + @echo "$(BIN_DIR)/$(NAME)" -build: $(LIB_DIR) $(BIN_DIR)/$(NAME) +preamble: $(LIB_DIR) $(BIN_DIR)/$(NAME) clean: - echo "# Clean application" - -rm -rf $(BIN_DIR) + @echo "# Clean application" -rm -rf $(TMP_DIR) $(LIB_DIR): @@ -147,7 +156,7 @@ $(BIN_DIR)/Info.plist: $(MAIN_DIR)/mac/main.plist echo APPLTINY > $(BIN_DIR)/PkgInfo $(BIN_DIR)/$(NAME): $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.c.o $(OBJECTS) - @echo "# cc" $(@F) "($@)" + @echo "# cc" $(@F) $(CC) $(LINK_FLAGS) $(XS_OBJECTS) $(TMP_DIR)/mc.xs.c.o $(TMP_DIR)/mc.resources.c.o $(OBJECTS) $(LIBRARIES) -o $@ $(XS_OBJECTS) : $(XS_HEADERS) From ac14bb6b2f9ee033d20a669649cb29137687c158 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 31 Dec 2020 18:22:47 -0400 Subject: [PATCH 30/32] Improved win threads & instrumentation builds --- contributed/cli/cli-win/main.c | 11 +++++------ contributed/cli/cli.c | 8 +++++++- modules/base/worker/pcWorker.c | 8 ++++++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/contributed/cli/cli-win/main.c b/contributed/cli/cli-win/main.c index a9a2314ecf..9dce16719c 100644 --- a/contributed/cli/cli-win/main.c +++ b/contributed/cli/cli-win/main.c @@ -43,7 +43,7 @@ unsigned int messagePumpThreadId = 0; // thread ID of the thread running t #define WM_APP_INSTRUMENTATION (WM_APP + 1) // ID of our private instrumentation message static VOID CALLBACK sendInstrumentationMessage(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - PostMessage(((txMachine *) screen.machine)->window, WM_APP_INSTRUMENTATION, 0, 0); + PostMessage(NULL, WM_APP_INSTRUMENTATION, 0, 0); } #endif @@ -100,11 +100,11 @@ void messagePump(char *pathToMod) { // set up a timer for the instrumentation #ifdef mxInstrument - SetTimer(((txMachine *) screen.machine)->window, 1, INSTRUMENTATION_FREQUENCY, sendInstrumentationMessage); + SetTimer(NULL, 1, INSTRUMENTATION_FREQUENCY, sendInstrumentationMessage); #endif // process the windows message loop until terminated - while( GetMessage(&msg, ((txMachine *) screen.machine)->window, 0, 0) > 0 ) { + while( GetMessage(&msg, NULL, 0, 0) > 0 ) { #ifdef mxInstrument if (msg.message == WM_APP_INSTRUMENTATION) { // make sure we don't issue instrumentation more often than once/INSTRUMENTATION_FREQUENCY - if @@ -134,17 +134,16 @@ void messagePump(char *pathToMod) { // create workers on every loop), the timer gets starved because Windows does not process timer // events unless the queue is empty. This will ensure that timers continue to operate even // when the loop is busy - while (PeekMessage(&msg, ((txMachine *) screen.machine)->window, WM_TIMER, WM_TIMER, PM_REMOVE)) { + while (PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } // similar problem as WM_TIMER for the WM_CLOSE message - it does get processed eventually, but to // speed it up we check here - if (PeekMessage(&msg, ((txMachine *) screen.machine)->window, WM_CLOSE, WM_CLOSE, PM_REMOVE)) + if (PeekMessage(&msg, NULL, WM_CLOSE, WM_CLOSE, PM_REMOVE)) break; } - // done - end our XS machine endMachine(); } diff --git a/contributed/cli/cli.c b/contributed/cli/cli.c index ba8af64214..37fd1c6bde 100644 --- a/contributed/cli/cli.c +++ b/contributed/cli/cli.c @@ -114,11 +114,15 @@ int startMachine(char *archivePath) { #ifdef mxInstrument // send the instrumentation headers, only if the debugger is connected +#ifdef mxDebug if (fxIsConnected(the)) +#endif fxDescribeInstrumentation(machine, 0, NULL, NULL); // send the initial instrumentation data, only if the debugger is connected +#ifdef mxDebug if (fxIsConnected(the)) +#endif fxSampleInstrumentation(the, 0, NULL); #endif { @@ -154,11 +158,13 @@ void endMachine() { Updates instrumentation (debugging statistics) for a running XS machine */ void instrumentMachine() { -#ifdef mxDebug +#ifdef mxInstrument xsBeginHost(screen.machine); { // is the debugger connected? If not, skip to avoid console output +#ifdef mxDebug if (fxIsConnected(the)) +#endif fxSampleInstrumentation(the, 0, NULL); } xsEndHost(the); diff --git a/modules/base/worker/pcWorker.c b/modules/base/worker/pcWorker.c index 8d03e2db32..5c9a28092f 100644 --- a/modules/base/worker/pcWorker.c +++ b/modules/base/worker/pcWorker.c @@ -103,8 +103,10 @@ void fxWorkerInitialize(txWorker* worker) xsCallFunction0(xsVar(0), xsGlobal); } xsEndHost(worker->machine); -#if mxInstrument +#ifdef mxInstrument +#ifdef mxDebug if (fxIsConnected(worker->machine)) +#endif fxDescribeInstrumentation(worker->machine, 0, NULL, NULL); #endif mxLockMutex(&worker->runningMutex); @@ -129,9 +131,11 @@ void fxWorkerMessage(void* machine, void* it) } } xsEndHost(machine); -#if mxInstrument +#ifdef mxInstrument if (((txScreen*)(((xsMachine*)machine)->host))->mainThread != mxCurrentThread()) +#ifdef mxDebug if (fxIsConnected(machine)) +#endif fxSampleInstrumentation(machine, 0, NULL); #endif c_free(job->argument); From bceb87311c71c674b7eee66a3f8a2f589546383d Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 4 Jan 2021 08:48:27 -0400 Subject: [PATCH 31/32] Reverted xsDebug - patch broker debug on workers --- xs/sources/xsDebug.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/xs/sources/xsDebug.c b/xs/sources/xsDebug.c index 7d84c124a6..9013b963a3 100644 --- a/xs/sources/xsDebug.c +++ b/xs/sources/xsDebug.c @@ -155,7 +155,6 @@ enum { }; static const char gxHexaDigits[] ICACHE_FLASH_ATTR = "0123456789ABCDEF"; -txBoolean _debugLoginAttempted = 0; // true once we have attempted fxLogin, to avoid connection delay when instantiating multiple machines (such as Workers) without a debugger void fxCheck(txMachine* the, txString thePath, txInteger theLine) { @@ -1795,10 +1794,7 @@ txBoolean fxIsModuleAvailable(txMachine* the, txSlot* realm, txSlot* module) void fxLogin(txMachine* the) { if (!fxIsConnected(the)) { - if (_debugLoginAttempted) - return; fxConnect(the); - _debugLoginAttempted = 1; if (!fxIsConnected(the)) return; } From 403e505d5588d90306bcba453d7e4930a35690d0 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 13 Jan 2021 13:40:20 -0400 Subject: [PATCH 32/32] Fixed incorrect duplicated platforms --- modules/files/preference/manifest.json | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/modules/files/preference/manifest.json b/modules/files/preference/manifest.json index b132b7ee71..e4a713d76c 100644 --- a/modules/files/preference/manifest.json +++ b/modules/files/preference/manifest.json @@ -55,13 +55,6 @@ "preference" ] }, - "cli-mac": { - "modules": { - "*": [ - "$(MODULES)/files/preference/mac/*" - ] - } - }, "win": { "modules": { "*": [ @@ -100,13 +93,6 @@ "$(MODULES)/files/preference/lin/*" ] } - }, - "cli-win": { - "modules": { - "*": [ - "$(MODULES)/files/preference/win/*" - ] - } } } }