diff --git a/contributed/cli/README.md b/contributed/cli/README.md new file mode 100644 index 0000000000..c1b312c7ee --- /dev/null +++ b/contributed/cli/README.md @@ -0,0 +1,45 @@ +# Command line (cli) controller + +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 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. + +## 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/cli-lin/main.c b/contributed/cli/cli-lin/main.c new file mode 100644 index 0000000000..d2bbb2b093 --- /dev/null +++ b/contributed/cli/cli-lin/main.c @@ -0,0 +1,149 @@ +/* + * 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 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. + + 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 "cli.h" +#include +#include +#include +#include + +static GtkApplication *gxApplication = NULL; +static GtkWindow *gxWindow; +static GtkApplication *app; + +#ifdef mxInstrument +/* + Updates Moddable instrumentation once/second - called from GTK timer (see onApplicationActivate for where + the timer is started) +*/ +gboolean sendInstrumentation(gpointer userData) { + instrumentMachine(); + return TRUE; +} +#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 shutdown. Cleanly terminates the XS machine. +*/ +void onApplicationShutdown(GtkApplication *app, gpointer it) { + // done - end our XS machine + endMachine(); +} + +/* + 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 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 activated, which happens if there are no commmand line arguments. We simply start up the + VM with no mods. +*/ +void onApplicationActivate(GtkApplication *app, gpointer it) { + startMachine(NULL); + +} + +/* + 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 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 +*/ +void ctrlHandler(int sig) { + fprintf(stderr, "\nShutting down\n"); + g_application_quit(G_APPLICATION(app)); +} + +/* + 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 +*/ +int main(int argc, char** argv) { + int status; + + // take control over ^C handling + signal(SIGINT, &ctrlHandler); + + 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); + g_signal_connect(app, "open", G_CALLBACK(onApplicationOpen), NULL); + status = g_application_run(G_APPLICATION(app), argc, argv); + + g_object_unref(app); + return status; +} diff --git a/contributed/cli/cli-mac/main.c b/contributed/cli/cli-mac/main.c new file mode 100644 index 0000000000..b548ec0eac --- /dev/null +++ b/contributed/cli/cli-mac/main.c @@ -0,0 +1,114 @@ +/* + * 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 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. +*/ + +#include "xsAll.h" +#include +#include +#include +#include "cli.h" +#include +#include +#include + +#ifdef mxInstrument +/* + 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 + +/* + 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 + instrumentation every second, and then the Mac message loop is executed. +*/ +int runMessageLoop(char *pathToMod) { + // start up our VM + int error = startMachine(pathToMod); + + // set up a timer for the instrumentation +#ifdef mxInstrument + CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 1, 1, 0, 0, sendInstrumentation, NULL); + CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes); +#endif + + // 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 instructs the CFRunLoop to shutdown +*/ +void ctrlHandler(int sig) { + fprintf(stderr, "\nShutting down\n"); + CFRunLoopStop(CFRunLoopGetCurrent()); +} + + +/* + 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 + signal(SIGINT, &ctrlHandler); + + // start up the XS VM and run the message loop + int error = runMessageLoop((argc > 1) ? argv[1] : NULL); + + return error; +} diff --git a/contributed/cli/cli-win/main.c b/contributed/cli/cli-win/main.c new file mode 100644 index 0000000000..9dce16719c --- /dev/null +++ b/contributed/cli/cli-win/main.c @@ -0,0 +1,184 @@ +/* + * 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 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 "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) { + PostMessage(NULL, WM_APP_INSTRUMENTATION, 0, 0); +} +#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 + 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, INSTRUMENTATION_FREQUENCY, 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/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 + INSTRUMENTATION_FREQUENCY; + 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); + + // 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, 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, NULL, WM_CLOSE, WM_CLOSE, PM_REMOVE)) + break; + } + // 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: + fprintf(stderr, "\nShutting down\n"); + PostMessage(((txMachine *) screen.machine)->window, 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/cli.c b/contributed/cli/cli.c new file mode 100644 index 0000000000..37fd1c6bde --- /dev/null +++ b/contributed/cli/cli.c @@ -0,0 +1,189 @@ +/* + * 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 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). +*/ + +#include "xsAll.h" +#include "mc.xs.h" +#include "cli.h" +#include "screen.h" + +// 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 +*/ +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; +} + +/* + 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"); + } + } + + // set up our "screen" context + mxCreateMutex(&screen.workersMutex); + screen.firstWorker = NULL; + screen.mainThread = mxCurrentThread(); + + // instantiate the VM + txMachine *machine = fxPrepareMachine(NULL, preparation, "machine", &screen, 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 +#ifdef mxDebug + machine->onBreak = debugBreak; +#endif + + // link our screen and machine objects together + screen.machine = (void *) machine; + machine->host = (void *) &screen; + + // set up the stack context for XS + xsBeginHost(machine); + { + xsVars(1); + +#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 + { + // 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() { + if (screen.machine) + xsDeleteMachine(screen.machine); +} + +/* + Updates instrumentation (debugging statistics) for a running XS machine +*/ +void instrumentMachine() { +#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); +#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/cli.h b/contributed/cli/cli.h new file mode 100644 index 0000000000..7ed2b1f796 --- /dev/null +++ b/contributed/cli/cli.h @@ -0,0 +1,25 @@ +/* + * 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(); +void *loadArchive(char *archivePath); + diff --git a/contributed/cli/manifest.json b/contributed/cli/manifest.json new file mode 100644 index 0000000000..583ee3f9cd --- /dev/null +++ b/contributed/cli/manifest.json @@ -0,0 +1,28 @@ +{ + "platforms": { + "cli-win": { + "modules": { + "*": [ + "./$(PLATFORM)/main", + "./cli" + ] + } + }, + "cli-mac": { + "modules": { + "*": [ + "./$(PLATFORM)/main", + "./cli" + ] + } + }, + "cli-lin": { + "modules": { + "*": [ + "./$(PLATFORM)/main", + "./cli" + ] + } + } + } +} \ No newline at end of file diff --git a/contributed/cli/screen.h b/contributed/cli/screen.h new file mode 100644 index 0000000000..ee3c1b4b6e --- /dev/null +++ b/contributed/cli/screen.h @@ -0,0 +1,81 @@ +/* + * 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; +}; \ No newline at end of file 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/*" ] } } 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 new file mode 100644 index 0000000000..17ba8e0098 --- /dev/null +++ b/examples/manifest_cli.json @@ -0,0 +1,40 @@ +{ + "include": [ + "$(MODDABLE)/contributed/cli/manifest.json" + ], + "modules": { + "*": [ + "$(MODULES)/base/timer/timer" + ] + }, + "preload": [ + ], + "platforms": { + "cli-win": { + "modules": { + "*": [ + "$(MODULES)/files/preference/win/*", + "$(MODULES)/base/timer/modTimer", + "$(MODULES)/base/timer/win/*" + ] + } + }, + "cli-lin": { + "modules": { + "*": [ + "$(MODULES)/files/preference/lin/*", + "$(MODULES)/base/timer/lin/*" + ] + } + }, + "cli-mac": { + "modules": { + "*": [ + "$(MODULES)/files/preference/mac/*", + "$(MODULES)/base/timer/modTimer", + "$(MODULES)/base/timer/mac/*" + ] + } + } + } +} diff --git a/examples/manifest_net.json b/examples/manifest_net.json index 39c506fa25..d298f61360 100644 --- a/examples/manifest_net.json +++ b/examples/manifest_net.json @@ -83,6 +83,52 @@ "net" ] }, + "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" + ] + }, + "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" + ] + }, + "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/examples/network/net/manifest.json b/examples/network/net/manifest.json index 1d95cd2a8f..ed30cdbf15 100644 --- a/examples/network/net/manifest.json +++ b/examples/network/net/manifest.json @@ -15,6 +15,9 @@ "qca4020": {}, "mac": {}, "win": {}, + "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 ce32cc986d..60597e596c 100644 --- a/modules/base/worker/manifest.json +++ b/modules/base/worker/manifest.json @@ -34,6 +34,21 @@ "*": "$(MODULES)/base/worker/pcWorker" } }, + "cli-lin": { + "modules": { + "*": "$(MODULES)/base/worker/pcWorker" + } + }, + "cli-mac": { + "modules": { + "*": "$(MODULES)/base/worker/pcWorker" + } + }, + "cli-win": { + "modules": { + "*": "$(MODULES)/base/worker/pcWorker" + } + }, "...": { "error": "Worker module unsupported" } diff --git a/modules/base/worker/pcWorker.c b/modules/base/worker/pcWorker.c index 3702f945bb..5c9a28092f 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" @@ -102,8 +103,11 @@ void fxWorkerInitialize(txWorker* worker) xsCallFunction0(xsVar(0), xsGlobal); } xsEndHost(worker->machine); -#if mxInstrument - fxDescribeInstrumentation(worker->machine, 0, NULL, NULL); +#ifdef mxInstrument +#ifdef mxDebug + if (fxIsConnected(worker->machine)) +#endif + fxDescribeInstrumentation(worker->machine, 0, NULL, NULL); #endif mxLockMutex(&worker->runningMutex); worker->running = 1; @@ -127,9 +131,12 @@ void fxWorkerMessage(void* machine, void* it) } } xsEndHost(machine); -#if mxInstrument +#ifdef mxInstrument if (((txScreen*)(((xsMachine*)machine)->host))->mainThread != mxCurrentThread()) - fxSampleInstrumentation(machine, 0, NULL); +#ifdef mxDebug + if (fxIsConnected(machine)) +#endif + fxSampleInstrumentation(machine, 0, NULL); #endif c_free(job->argument); } diff --git a/modules/files/file/manifest.json b/modules/files/file/manifest.json index d1d30cd7bb..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,6 +54,16 @@ } } }, + "cli-win": { + "modules": { + "*": "$(MODULES)/files/file/win/*" + }, + "config": { + "file": { + "root": "./" + } + } + }, "lin": { "modules": { "*": "$(MODULES)/files/file/lin/*" @@ -64,6 +74,16 @@ } } }, + "cli-lin": { + "modules": { + "*": "$(MODULES)/files/file/lin/*" + }, + "config": { + "file": { + "root": "/tmp/" + } + } + }, "qca4020": { "modules": { "*": "$(MODULES)/files/file/qca4020/*" diff --git a/modules/network/wifi/manifest.json b/modules/network/wifi/manifest.json index 514a5c3a84..965c2c1a82 100644 --- a/modules/network/wifi/manifest.json +++ b/modules/network/wifi/manifest.json @@ -23,6 +23,13 @@ ] } }, + "cli-lin": { + "modules": { + "*": [ + "$(MODULES)/network/wifi/sim/*" + ] + } + }, "mac": { "modules": { "*": [ @@ -30,6 +37,13 @@ ] } }, + "cli-mac": { + "modules": { + "*": [ + "$(MODULES)/network/wifi/sim/*" + ] + } + }, "win": { "modules": { "*": [ @@ -37,6 +51,13 @@ ] } }, + "cli-win": { + "modules": { + "*": [ + "$(MODULES)/network/wifi/sim/*" + ] + } + }, "qca4020": { "modules": { "*": [ diff --git a/tools/mcconfig.js b/tools/mcconfig.js index 2a5295acf2..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,21 @@ 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"; + 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/make.cli-lin.mk b/tools/mcconfig/make.cli-lin.mk new file mode 100644 index 0000000000..0a87a5e66a --- /dev/null +++ b/tools/mcconfig/make.cli-lin.mk @@ -0,0 +1,206 @@ +# +# 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: 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)" + +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 + +$(XS_OBJECTS) : $(XS_HEADERS) +$(LIB_DIR)/%.c.o: %.c + @echo "# cc" $(. +# + +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: 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)" + +preamble: $(LIB_DIR) $(BIN_DIR)/$(NAME) + +clean: + @echo "# Clean application" + -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" $(. +# + +!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: $(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 + echo $(TMP_DIR) + del /s/q/f $(TMP_DIR)\*.* > NULL + rmdir /s/q $(TMP_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 + 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) <. +# + +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 + diff --git a/tools/mcrun/make.cli-mac.mk b/tools/mcrun/make.cli-mac.mk new file mode 100644 index 0000000000..7596badf2f --- /dev/null +++ b/tools/mcrun/make.cli-mac.mk @@ -0,0 +1,50 @@ +# +# 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) + 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 + diff --git a/tools/mcrun/nmake.cli-win.mk b/tools/mcrun/nmake.cli-win.mk new file mode 100644 index 0000000000..8aff06d9e2 --- /dev/null +++ b/tools/mcrun/nmake.cli-win.mk @@ -0,0 +1,42 @@ +# +# Copyright (c) 2016-2017 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 . +# + +!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)