Modernize, merge ARM macOS support from @incidentist

This commit is contained in:
NotAlexNoyle committed 2026-06-14 09:26:48 -04:00
commit e313b97dc3
5 files changed
+72 -77

No files matched your search

+8 -1
View File
@@ -1 +1,8 @@
build-novacomd-host/
build-*
*.swp
*~
tags
TAGS
*.orig
cscope.*
*.dSYM
+27 -11
View File
@@ -1,31 +1,47 @@
novacomd
========
A 2025 build of novacomd adapted for UNIX-like hosts using libusb-compat-0.1.
A 2026 build of novacomd for UNIX-like hosts built on top of libusb-compat-0.1. novacomd runs as a daemon or service on the host and the device.
Before building:
## Dependencies
*This command will vary depending on your distribution.*
> doas xbps-install -Su libusb-compat-devel
Building from source needs a C compiler (GCC or Clang), **GNU make**, and **libusb-compat-0.1**.
To build:
Get a compiler:
* **macOS:** Apple's Clang and make come with the Xcode Command Line Tools (`xcode-select --install`).
* **Linux:** install your distribution's build tools (`build-essential` on Debian/Ubuntu, `base-devel` on Arch, etc.).
Get libusb-compat-0.1:
| Platform | Command |
| --- | --- |
| macOS (Homebrew) | `brew install libusb-compat` |
| Debian / Ubuntu | `sudo apt install libusb-dev` |
| Fedora | `sudo dnf install libusb-compat-0.1-devel` |
| Arch | `sudo pacman -S libusb-compat` |
| Void | `doas xbps-install -Su libusb-compat-devel` |
(On Debian/Ubuntu the libusb-0.1 development package is named `libusb-dev`; `libusb-1.0-0-dev` is a legacy, unused package.)
## Building
> ./install-novacomd-linux.sh
_On machines with GCC 15 or later, the following command should be run instead:_
To force a specific compiler, set `CC`, for example:
> CC="gcc -std=gnu17" ./install-novacomd-linux.sh
To install:
To install, copy or symlink `build-novacomd-host/novacomd` to the `/bin` directory of your Palm SDK install (usually `/opt/nova/bin`).
*May not require privilege escalation depending on your install location.*
> doas mv build-novacomd-host/* /YOUR/LOCATION/HERE/
novacomd runs as a daemon or service on the host and the device.
> mv build-novacomd-host/novacomd /YOUR/LOCATION/HERE/
![In Action](https://i.imgur.com/GUqOYEp.png)
# Copyright and License Information
Thanks to [incidentist](https://github.com/incidentist/novacomd) for the macOS build support.
## Copyright
Unless otherwise specified, all content, including all source code files
and documentation files in this repository are:
+35 -62
View File
@@ -1,24 +1,17 @@
#!/usr/bin/env bash
#
# Build and install novacomd (NotAlexNoyle's 2025 libusb-compat fork) on a UNIX-like host.
# Build and (optionally) install novacomd -- NotAlexNoyle's 2025 libusb-compat fork.
#
# Run this from the novacomd source directory (the directory that holds the makefile), or
# point it at that directory with $NOVACOMD_SRC or the first argument. With no privileges it
# builds only. When run as root (e.g. via sudo or doas) it builds as the invoking
# unprivileged user and then installs the resulting binary into $INSTALL_DIR so it lands on
# PATH.
# Run from the novacomd source dir, or point at it with $NOVACOMD_SRC or the first argument.
# Unprivileged: builds only. As root (sudo/doas): builds as the invoking user, then installs.
#
# Environment overrides:
# NOVACOMD_SRC novacomd source directory. Default: this script's directory.
# CC C compiler, simple whitespace-separated form only (e.g. "gcc -std=gnu17").
# Auto-set to "gcc -std=gnu17" on GCC >= 15 when unset. Quoted/escaped
# arguments and compiler paths containing spaces are not supported.
# INSTALL_DIR Install location for the novacomd binary. Default: /usr/local/bin
# JOBS Parallel make jobs (positive integer). Default: detected CPU count.
# NOVACOMD_SRC source directory (default: this script's directory)
# CC C compiler (default: gcc/cc + -std=gnu17 when supported; whitespace-split, no quoted args)
# INSTALL_DIR install location (default: /usr/local/bin)
# JOBS parallel make jobs (default: CPU count)
#
# Exit status: 0 on success, non-zero on any failure.
#
# This is free and unencumbered software released into the public domain.
# Exit status: 0 on success, non-zero on failure. Public domain.
# Author: NotAlexNoyle (alexnoyle@icloud.com)
set -u
@@ -31,78 +24,60 @@ log() { printf 'novacomd-install: %s\n' "$*"; }
err() { printf 'novacomd-install: ERROR: %s\n' "$*" >&2; }
die() { err "$*"; exit 1; }
# --- locate the source tree ------------------------------------------------
# Precedence: $1, then $NOVACOMD_SRC, then this script's own (symlink-resolved) directory.
# --- locate the source tree ---
# Source precedence: argument 1, then $NOVACOMD_SRC, then this script's own directory.
self="$(readlink -f -- "${BASH_SOURCE[0]}" 2>/dev/null || printf '%s' "${BASH_SOURCE[0]}")"
script_dir="$(cd -- "$(dirname -- "$self")" >/dev/null 2>&1 && pwd -P)"
src_dir="${1:-${NOVACOMD_SRC:-$script_dir}}"
cd -- "$src_dir" >/dev/null 2>&1 || die "cannot enter novacomd source directory: $src_dir"
src_dir="$(pwd -P)"
if [ ! -f makefile ] && [ ! -f Makefile ]; then
die "no makefile in $src_dir -- pass the novacomd source directory as the first argument."
fi
[ -f makefile ] || [ -f Makefile ] || die "no makefile in $src_dir -- pass the source directory as the first argument."
# --- privilege model -------------------------------------------------------
# The toolchain (compiler + make recipes) must never run as root. When invoked as root via
# sudo or doas, drop to the invoking user for every toolchain call; refuse if that is not
# possible. sudo exports SUDO_USER, doas exports DOAS_USER.
# --- privilege model ---
# The build toolchain must never run as root; when root, drop to the invoking user for every build step.
orig_user="${SUDO_USER:-${DOAS_USER:-}}"
builder_prefix=()
if (( EUID == 0 )); then
# Resolve the invoking user to a UID and require a real, non-root account (catches UID-0
# aliases, not just the literal name "root").
builder_uid="$(id -u "$orig_user" 2>/dev/null || true)"
if [ -n "$orig_user" ] && [[ "$builder_uid" =~ ^[1-9][0-9]*$ ]] \
&& command -v runuser >/dev/null 2>&1; then
builder_uid="$(id -u "$orig_user" 2>/dev/null || true)" # require a real, non-root account (UID > 0)
if [ -n "$orig_user" ] && [[ "$builder_uid" =~ ^[1-9][0-9]*$ ]] && command -v runuser >/dev/null 2>&1; then
builder_prefix=(runuser -u "$orig_user" --)
else
die "refusing to run the build toolchain as root. Run this script as a normal user; \
it will only ask for elevation to install."
die "refusing to build as root -- run as a normal user; elevation is only used to install."
fi
fi
as_builder() { "${builder_prefix[@]}" "$@"; }
# --- preflight: build tools ------------------------------------------------
command -v make >/dev/null 2>&1 \
|| die "'make' not found. Install your distribution's build tools (build-essential / base-devel)."
# --- preflight: build tools ---
command -v make >/dev/null 2>&1 || die "'make' not found -- install your build tools (build-essential / base-devel)."
# --- compiler selection ----------------------------------------------------
# GCC 15 defaults to C23, which rejects this older code; pin gnu17 there.
# --- compiler selection ---
# Default the compiler when CC is unset, and add -std=gnu17 only if accepted (C23-default compilers need it).
if [ -z "${CC:-}" ]; then
if command -v gcc >/dev/null 2>&1; then
gcc_ver="$(as_builder gcc -dumpfullversion -dumpversion 2>/dev/null)"
gcc_major="${gcc_ver%%.*}"
case "$gcc_major" in
''|*[!0-9]*) : ;; # unknown format -> leave CC unset
*) [ "$gcc_major" -ge 15 ] && CC="gcc -std=gnu17" ;;
esac
if command -v gcc >/dev/null 2>&1; then CC=gcc; else CC=cc; fi
if printf 'int main(void){return 0;}\n' | as_builder $CC -std=gnu17 -fsyntax-only -xc - >/dev/null 2>&1; then
CC="$CC -std=gnu17"
fi
fi
CC="${CC:-cc}"
# CC may carry flags ("gcc -std=gnu17"); split into an argv array for direct invocation.
# Split CC ("gcc -std=gnu17") into an argv array, then confirm a compiler is set and exists.
read -r -a cc_argv <<<"$CC"
[ "${#cc_argv[@]}" -gt 0 ] || die "CC is empty -- set it to a C compiler, e.g. CC=gcc."
command -v "${cc_argv[0]}" >/dev/null 2>&1 || die "C compiler not found: ${cc_argv[0]}"
# --- preflight: libusb-compat header ---------------------------------------
# The host transport needs libusb-compat-0.1 (<usb.h>). Probe early for a clear message.
if ! printf '#include <usb.h>\nint main(void){return 0;}\n' \
| as_builder "${cc_argv[@]}" -fsyntax-only -xc - >/dev/null 2>&1; then
die "could not compile a <usb.h> probe -- the libusb-compat-0.1 dev headers are most likely
missing. Install them, e.g.:
# --- preflight: libusb-compat header ---
# The host transport needs libusb-compat-0.1 (<usb.h>); probe for it up front for a clear message.
if ! printf '#include <usb.h>\nint main(void){return 0;}\n' | as_builder "${cc_argv[@]}" -fsyntax-only -xc - >/dev/null 2>&1; then
die "missing libusb-compat-0.1 (<usb.h>). Install it, e.g.:
Debian/Ubuntu: sudo apt install libusb-dev
Fedora: sudo dnf install libusb-compat-0.1-devel
Void: doas xbps-install -Su libusb-compat-devel
Arch: sudo pacman -S libusb-compat"
fi
# --- build -----------------------------------------------------------------
# Validate JOBS and neutralize inherited make flags so the build cannot be turned into a
# no-op (e.g. JOBS or MAKEFLAGS carrying -n/--version, which would exit 0 without building).
if [ -z "${JOBS:-}" ]; then
JOBS="$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1)"
fi
# --- build ---
# Default JOBS to the CPU count, and clear inherited make flags that could turn the build into a no-op.
[ -n "${JOBS:-}" ] || JOBS="$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1)"
[[ "$JOBS" =~ ^[1-9][0-9]*$ ]] || JOBS=1
unset MAKEFLAGS MFLAGS GNUMAKEFLAGS MAKEFILES
@@ -111,8 +86,7 @@ as_builder make -j"$JOBS" CC="$CC" host || die "build failed -- see the compiler
[ -f "$BUILD_BIN" ] && [ -x "$BUILD_BIN" ] || die "build reported success but $BUILD_BIN is missing."
log "build succeeded: $BUILD_BIN"
# --- install ---------------------------------------------------------------
# Only attempt the system install when running with the privilege for it.
# --- install (root only) ---
if (( EUID == 0 )); then
dest="$INSTALL_DIR/$TARGET"
[ -d "$dest" ] && die "install destination is a directory: $dest"
@@ -122,9 +96,8 @@ if (( EUID == 0 )); then
[ -f "$dest" ] && [ -x "$dest" ] || die "post-install check failed: $dest"
log "installed: $dest"
else
# Build-only run: suggest the right elevation tool for a manual install (doas or sudo).
elevate="sudo"
command -v doas >/dev/null 2>&1 && elevate="doas"
# Not root: print the manual install command using whichever elevation tool is available.
if command -v doas >/dev/null 2>&1; then elevate="doas"; else elevate="sudo"; fi
log "not running as root -- skipping install."
log "to install: $elevate install -T -m 0755 '$src_dir/$BUILD_BIN' '$INSTALL_DIR/$TARGET'"
fi
+2 -2
View File
@@ -39,7 +39,7 @@ CFLAGS :=
ifneq ($(MACHINE),)
MYCFLAGS += -DMACHINE=\"$(MACHINE)\"
endif
HOSTCFLAGS := $(MYCFLAGS) $(CFLAGS) -Isrc
HOSTCFLAGS := $(MYCFLAGS) $(CFLAGS) -Isrc -DPLATFORM_PTHREADS=1
DEVICECFLAGS := $(MYCFLAGS) $(OECFLAGS) $(TARGET_CC_ARCH) -DPLATFORM_PTHREADS=1
CPPFLAGS := -g
ASMFLAGS :=
@@ -62,7 +62,7 @@ DEVICELD := arm-none-linux-gnueabi-ld
endif
ifeq ($(UNAME),Linux)
ifeq ($(UNAME), $(filter $(UNAME), Linux Darwin))
LDFLAGS += -Wl,-rpath,. # add the local path to the program's search path
HOSTLDLIBS += -lpthread -lusb
HOSTPLATFORM := pthreads
-1
View File
@@ -33,7 +33,6 @@
#include <log.h>
#include <sys/queue.h>
#include <linux/usbdevice_fs.h>
#include "../novacom/mux.h"
#include "device_list.h"