Skip to content

Adding Embedded Linux platform #1480

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: public
Choose a base branch
from

Conversation

linfan68
Copy link

@linfan68 linfan68 commented Apr 3, 2025

This pull request introduces support for the linemb platform, targeting embedded Linux devices such as the Raspberry Pi Zero. The changes include updates to several configuration and source files to ensure compatibility and functionality for this new platform.
The original disscussion: Running on ARM Linux boards (Raspberry Pi Zero)

The most important changes are summarized below:

Main Entrance for new platform:

Build System:

  • Added tools/mcconfig/make.linemb.mk to define the build process for the linemb platform, including toolchain configurations and compilation flags.

Platform-Specific Headers:

  • Added a new platform header file xs/platforms/linemb/xsPlatform_linemb.h to define platform-specific macros and include necessary headers for the linemb platform.

Platform Support:

  • Added linemb platform configuration in various manifest.json files to include necessary modules and settings for the linemb platform. [1] [2] [3] [4] [5] [6] [7] [8] [9]

Documentation:

  • Created a new documentation file documentation/devices/linemb.md to guide users on setting up and using the Moddable SDK with embedded Linux devices. This includes preparation steps, toolchain installation, and sample project build instructions.

@linfan68
Copy link
Author

linfan68 commented Apr 5, 2025

I will add this for "why we need this new platform?" in the linemb.md file. Please also comment on new use cases:

  1. Ultra-Low Resource Consumption on Small Linux Devices​​
    Moddable's embedded JS runtime requires minimal memory and CPU resources compared to Node.js, making it ideal for resource-constrained IoT devices. For example, Node.js processes in production environments often consume 200MB+ RSS memory, while Moddable operates efficiently even on microcontrollers like ESP32. Its lightweight architecture (designed for low-cost hardware) enables faster startup times and lower RAM/ROM footprints.
  2. ​​Single-Executable Deployment​​
    The platform eliminates dependency sprawl by bundling all required components into one self-contained executable. This contrasts with Node.js' heavy reliance on npm modules and system libraries. Moddable's integrated SDK approach ensures portable deployment without complex environment configurations.
  3. ​​Seamless C Language Interoperability​​
    Native extensions in Moddable require minimal boilerplate compared to Node.js' N-API/V8 binding complexities. Developers can directly invoke C functions from JavaScript via XS engine bindings, similar to embedded C development paradigms. This enables hybrid apps combining JS logic with hardware-level C optimizations and hardware operation.
  4. ​​Cross-Environment Testing via Hardware Abstraction​​
    With a robust Hardware Abstraction Layer (HAL), automated tests targeting embedded devices can run unmodified on Linux servers for CI/CD pipelines.

Copy link
Collaborator

@phoddie phoddie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks quite good. Please let me know if you have any questions about the comments.

Comment on lines 125 to 145

c_memset(the, 0, sizeof(txMachine));
the->preparation = preparation;
the->keyArray = preparation->keys;
the->keyCount = (txID)preparation->keyCount + (txID)preparation->creation.initialKeyCount;
the->keyIndex = (txID)preparation->keyCount;
the->nameModulo = preparation->nameModulo;
the->nameTable = preparation->names;
the->symbolModulo = preparation->symbolModulo;
the->symbolTable = preparation->symbols;

the->stack = &preparation->stack[0];
the->stackBottom = &preparation->stack[0];
the->stackTop = &preparation->stack[preparation->stackCount];

the->firstHeap = &preparation->heap[0];
the->freeHeap = &preparation->heap[preparation->heapCount - 1];
the->aliasCount = (txID)preparation->aliasCount;

setvbuf(stdout, NULL, _IONBF, 0);
the = fxCloneMachine(&preparation->creation, the, "linemb", NULL);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more-or-less xsPrepareMachine (implemented in fxPrepareMachine). If possible, it would be more maintainable to use the xsPrepareMachine.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 221 to 231
const char *gXSAbortStrings[] ICACHE_FLASH_ATTR = {
"debugger",
"memory full",
"stack overflow",
"fatal",
"dead strip",
"unhandled exception",
"not enough keys",
"too much computation",
"unhandled rejection"
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use fxAbortString() instead of maintaining your own list of abort strings (the function was added very recently)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

void fxAbort(xsMachine *the, int status)
{
const char *msg = (status <= XS_UNHANDLED_REJECTION_EXIT) ? gXSAbortStrings[status] : "unknown";
#if 0 // MODDEF_XS_ABORTHOOK
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recall you had a question about the abort hook. Is this disabled because you weren't able to resolve that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phoddie Actually the abort hook works... But I was having trouble figuring out how to make MODDEF_XS_ABORTHOOK defined... somehow adding this

	"defines": {
		"xs": {
			"abortHook": 1
		}
	}

does not get MODDEF_XS_ABORTHOOK defined

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MODDEF_XS_ABORTHOOK should be defined in mc.defines.h. It looks like main.c isn't including that?

#include "mc.defines.h"

Comment on lines 72 to 84
static void fatal_error_handler(int signum) {
const char* signame = "UNKNOWN";
switch(signum) {
case SIGABRT: signame = "SIGABRT"; break;
case SIGFPE: signame = "SIGFPE"; break;
case SIGILL: signame = "SIGILL"; break;
case SIGINT: signame = "SIGINT"; break;
case SIGQUIT: signame = "SIGQUIT"; break;
case SIGSEGV: signame = "SIGSEGV"; break;
case SIGTERM: signame = "SIGTERM"; break;
case SIGBUS: signame = "SIGBUS"; break;
case SIGPIPE: signame = "SIGPIPE"; break;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is strsignal() an option here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 8 to 11
"platforms": {
"linemb/*": {
"strip": []
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"helloworld", and most applications, shouldn't need a platform specific section of its manifest.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I have a question here. After syncing recent code, I'm getting "Aborting with status 4, dead strip" error, unless adding this config to disable stripping. I assume there are some book keeping logic mssing here.

On the other hand, given there should be (relatively) plenty of memory on those linux chips, it might be a good idea to disable stripping?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After syncing recent code, I'm getting "Aborting with status 4, dead strip" error, unless adding this config to disable stripping. I assume there are some book keeping logic missing here.

I wonder if that is because you allow for top-level await in the host (which is fine) but no script uses a promise or async/await (for example, in helloworld).

On the other hand, given there should be (relatively) plenty of memory on those linux chips, it might be a good idea to disable stripping?

Your host can certainly make that choice. A project can still enable engine stripping if it wants to. The default for "strip" is set in manifest_base.json. I think you can simply override that in your host's manifest.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@@ -0,0 +1,129 @@
# Using the Moddable SDK with embedded Linux (Raspberry Pi Zero)
This is a demo document to demostration how to bring up an embedded Linux device with the Moddable SDK.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"demonstrate" in place of "demostration"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@phoddie
Copy link
Collaborator

phoddie commented Apr 30, 2025

@linfan68 – we were thinking we could include this in our May release if you are able to resolve the comments.. Any chance of that in the coming days? Thanks!

@mkellner
Copy link
Collaborator

mkellner commented May 4, 2025

Hello @linfan68. I am trying with Ubuntu 22.04.4 LTS x86_64 host.

I get this error trying to build linemb/armhf

.../moddable/xs/platforms/lin_xs.h:57:10: fatal error: gio/gio.h: No such file or directory
   57 | #include <gio/gio.h>

@linfan68
Copy link
Author

@linfan68 – we were thinking we could include this in our May release if you are able to resolve the comments.. Any chance of that in the coming days? Thanks!

Sorry I just had a crazy week.... sure I'll try to resolve these comments in the coming days.

@linfan68
Copy link
Author

#include <gio/gio.h>

HI @mkellner , where did you see this error? When building moddable tools?

@linfan68
Copy link
Author

@linfan68 – we were thinking we could include this in our May release if you are able to resolve the comments.. Any chance of that in the coming days? Thanks!

I've resolved most of the comments. Also fixed an issue that caused 100% cpu... faeec84

I'll test the error handling code a little bit before finalized this PR. Also please give me some pointers on the abortHook issue I mentioned above。

@mkellner
Copy link
Collaborator

mkellner commented May 13, 2025

#include <gio/gio.h>

HI @mkellner , where did you see this error? When building moddable tools?

No. This was buildhost: Ubuntu 22.04.4 LTS, target: linemb/arm64 building helloworld.

@linfan68
Copy link
Author

#include <gio/gio.h>

HI @mkellner , where did you see this error? When building moddable tools?

No. This was buildhost: Ubuntu 22.04.4 LTS, target: linemb/arm64 building helloworld.

Found the problem, you need glib for arm64

sudo apt-get install libglib2.0-dev:arm64

I'll update the document

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants