Odroid N2: Manually built AppImage fails to run

Building a linux-x64 image works fine and it runs without this error output on this Intel machine here.

Building a linux-arm64 image does not work on my Odroid N2. The command was:
npm install && npm run build-latest && npm run build:linux-arm64

I ran this command from another local machine in my network but I get the same output if I run it directly on the Odroid N2.

mcguirk$ DISPLAY=:0 ~/bin/gSender-1.0.7-latest-arm64.AppImage
MESA-LOADER: failed to retrieve device information
MESA-LOADER: failed to retrieve device information
MESA-LOADER: failed to retrieve device information
MESA-LOADER: failed to open zink: /usr/lib/dri/zink_dri.so: cannot open shared object file: Permission denied (search paths /usr/lib/dri, suffix _dri)
failed to load driver: zink
MESA-LOADER: failed to open kms_swrast: /usr/lib/dri/kms_swrast_dri.so: cannot open shared object file: Permission denied (search paths /usr/lib/dri, suffix _dri)
failed to load driver: kms_swrast
MESA-LOADER: failed to open swrast: /usr/lib/dri/swrast_dri.so: cannot open shared object file: Permission denied (search paths /usr/lib/dri, suffix _dri)
failed to load swrast driver
04:02:09.247 › Error: /tmp/.mount_gSendeszbIuu/resources/app/node_modules/@serialport/bindings/build/Release/bindings.node: cannot open shared object file: No such file or directory
    at process.func [as dlopen] (node:electron/js2c/asar_bundle:5:1812)
    at Object.Module._extensions..node (node:internal/modules/cjs/loader:1199:18)
    at Object.func [as .node] (node:electron/js2c/asar_bundle:5:1812)
    at Module.load (node:internal/modules/cjs/loader:988:32)
    at Module._load (node:internal/modules/cjs/loader:829:12)
    at Function.c._load (node:electron/js2c/asar_bundle:5:13343)
    at Module.require (node:internal/modules/cjs/loader:1012:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at bindings (/tmp/.mount_gSendeszbIuu/resources/app/node_modules/bindings/bindings.js:112:48)
    at Object.<anonymous> (/tmp/.mount_gSendeszbIuu/resources/app/node_modules/@serialport/bindings/lib/linux.js:2:36)
    at Module._compile (node:internal/modules/cjs/loader:1116:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1169:10)
    at Module.load (node:internal/modules/cjs/loader:988:32)
    at Module._load (node:internal/modules/cjs/loader:829:12)
    at Function.c._load (node:electron/js2c/asar_bundle:5:13343)
    at Module.require (node:internal/modules/cjs/loader:1012:19)
(node:8256) UnhandledPromiseRejectionWarning: TypeError: Message must be a string
    at messageBox (node:electron/js2c/browser_init:49:3930)
    at Object.showMessageBox (node:electron/js2c/browser_init:49:5487)
    at _callee4$ (/tmp/.mount_gSendeszbIuu/resources/app/main.js:353:37)
    at tryCatch (/tmp/.mount_gSendeszbIuu/resources/app/node_modules/regenerator-runtime/runtime.js:63:40)
    at Generator.invoke [as _invoke] (/tmp/.mount_gSendeszbIuu/resources/app/node_modules/regenerator-runtime/runtime.js:294:22)
    at Generator.throw (/tmp/.mount_gSendeszbIuu/resources/app/node_modules/regenerator-runtime/runtime.js:119:21)
    at asyncGeneratorStep (/tmp/.mount_gSendeszbIuu/resources/app/main.js:53:103)
    at _throw (/tmp/.mount_gSendeszbIuu/resources/app/main.js:55:291)
(Use `gsender --trace-warnings ...` to show where the warning was created)
(node:8256) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3)

mcguirk$ ls -l /tmp/.mount_gSendeszbIuu/resources/app/node_modules/@serialport/bindings/build/Release/bindings.node
-rwxr-xr-x 1 root root 76600 May 14 02:57 /tmp/.mount_gSendeszbIuu/resources/app/node_modules/@serialport/bindings/build/Release/bindings.node

Note that the bindings.node file exists in that /tmp subdirectory. I put the AppImage process in the background with ctrl-Z and ran ls.

Any help will be greatly appreciated. I have just elementary experience with nodeJS and I’m in over my head here.

Thanks!

So I finally got this ironed out, and the .AppImage works on both my Odroid N2 and my RPi 4, as far as I can tell. Here is a hacky document showing what I did on my Odroid N2:

Compile gSender on the arm64 machine. It will not work if cross-compiled on a machine with a different cpu architecture.

Install nvm (Node Version Manager)

Use nvm to install node 14

$ nvm install 14
$ nvm use 14 # maybe you run a different node version? (may not need this line but it won’t hurt)

Install yarn (needed for build)

$ npm install -g yarn # this works, there may be a better way

Download gsender source code as .tar.gz file

$ tar xf <gsender_source_code.tar.gz>

The “deb” and “rpm” targets call an x86 version of fpm and the build will fail. Edit package.json and remove the “deb” and “rpm” targets. Save it.

$ cd gsender-
$ nano package.json

"linux": {
  "category": "Utility",
  "target": [
    "AppImage"
  ]
}

Compile the .AppImage

$ npm install && npm run build-latest && npm run build:linux-arm64

The .AppImage file will be in the output/ subdirectory. Check it out

$ cd output
$ ./gSender--latest-arm64.AppImage

If you need the “deb” and “rpm” targets, see this page for a possible fpm fix: