Skip to content

Commit 3765085

Browse files
authored
Leverage prebuildify to provide prebuilt addon for npm package (#1287)
This PR introduces prebuildify support to provide prebuilt addon binaries for the npm package, eliminating the need to compile from source in many cases. The changes implement a smart native addon loader that prioritizes prebuilt binaries while maintaining fallback compilation capabilities. Key changes: - Replaced direct `bindings()` calls with a custom `native_loader.js` module across all files - Added prebuild infrastructure with scripts for installation, tagging, and CI workflows - Updated package.json to include prebuildify tooling and modified installation flow Fix: #1286
1 parent d4d2d7c commit 3765085

37 files changed

+625
-36
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: Prebuild Linux ARM64
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
tags:
7+
- '*'
8+
9+
jobs:
10+
prebuild:
11+
runs-on: ubuntu-24.04-arm
12+
container:
13+
image: ${{ matrix.docker_image }}
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
node-version: [22.X]
18+
architecture: [arm64]
19+
ros_distribution:
20+
- humble
21+
- jazzy
22+
- kilted
23+
include:
24+
# Humble Hawksbill (May 2022 - May 2027)
25+
- docker_image: ubuntu:jammy
26+
ros_distribution: humble
27+
ubuntu_codename: jammy
28+
# Jazzy Jalisco (May 2024 - May 2029)
29+
- docker_image: ubuntu:noble
30+
ros_distribution: jazzy
31+
ubuntu_codename: noble
32+
# Kilted Kaiju (May 2025 - Dec 2026)
33+
- docker_image: ubuntu:noble
34+
ros_distribution: kilted
35+
ubuntu_codename: noble
36+
37+
steps:
38+
- name: Setup Node.js ${{ matrix.node-version }} on ${{ matrix.architecture }}
39+
uses: actions/setup-node@v5
40+
with:
41+
node-version: ${{ matrix.node-version }}
42+
architecture: ${{ matrix.architecture }}
43+
44+
- name: Setup ROS2
45+
uses: ros-tooling/[email protected]
46+
with:
47+
required-ros-distributions: ${{ matrix.ros_distribution }}
48+
49+
- uses: actions/checkout@v5
50+
51+
- name: Install dependencies
52+
shell: bash
53+
run: |
54+
source /opt/ros/${{ matrix.ros_distribution }}/setup.bash
55+
npm i
56+
57+
- name: Generate prebuilt binary
58+
shell: bash
59+
run: |
60+
source /opt/ros/${{ matrix.ros_distribution }}/setup.bash
61+
npm run prebuild
62+
63+
- name: Upload prebuilt binary
64+
uses: actions/upload-artifact@v4
65+
with:
66+
name: prebuilt-linux-arm64-node${{ matrix.node-version }}-${{ matrix.ubuntu_codename }}-${{ matrix.ros_distribution }}
67+
path: prebuilds/linux-arm64/*.node
68+
if-no-files-found: error
69+
70+
- name: Test loading prebuilt
71+
shell: bash
72+
run: |
73+
source /opt/ros/${{ matrix.ros_distribution }}/setup.bash
74+
node -e "
75+
const rclnodejs = require('./index.js');
76+
console.log('Successfully loaded rclnodejs with prebuilt binary');
77+
console.log('Platform:', process.platform, 'Arch:', process.arch);
78+
console.log('ROS_DISTRO:', process.env.ROS_DISTRO);
79+
"
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: Prebuild Linux x64
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
tags:
7+
- '*'
8+
9+
jobs:
10+
prebuild:
11+
runs-on: ubuntu-latest
12+
container:
13+
image: ${{ matrix.docker_image }}
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
node-version: [22.X]
18+
architecture: [x64]
19+
ros_distribution:
20+
- humble
21+
- jazzy
22+
- kilted
23+
include:
24+
# Humble Hawksbill (May 2022 - May 2027)
25+
- docker_image: ubuntu:jammy
26+
ros_distribution: humble
27+
ubuntu_codename: jammy
28+
# Jazzy Jalisco (May 2024 - May 2029)
29+
- docker_image: ubuntu:noble
30+
ros_distribution: jazzy
31+
ubuntu_codename: noble
32+
# Kilted Kaiju (May 2025 - Dec 2026)
33+
- docker_image: ubuntu:noble
34+
ros_distribution: kilted
35+
ubuntu_codename: noble
36+
37+
steps:
38+
- name: Setup Node.js ${{ matrix.node-version }} on ${{ matrix.architecture }}
39+
uses: actions/setup-node@v5
40+
with:
41+
node-version: ${{ matrix.node-version }}
42+
architecture: ${{ matrix.architecture }}
43+
44+
- name: Setup ROS2
45+
uses: ros-tooling/[email protected]
46+
with:
47+
required-ros-distributions: ${{ matrix.ros_distribution }}
48+
49+
- uses: actions/checkout@v5
50+
51+
- name: Install dependencies
52+
shell: bash
53+
run: |
54+
source /opt/ros/${{ matrix.ros_distribution }}/setup.bash
55+
npm i
56+
57+
- name: Generate prebuilt binary
58+
shell: bash
59+
run: |
60+
source /opt/ros/${{ matrix.ros_distribution }}/setup.bash
61+
npm run prebuild
62+
63+
- name: Upload prebuilt binary
64+
uses: actions/upload-artifact@v4
65+
with:
66+
name: prebuilt-linux-x64-node${{ matrix.node-version }}-${{ matrix.ubuntu_codename }}-${{ matrix.ros_distribution }}
67+
path: prebuilds/linux-x64/*.node
68+
if-no-files-found: error
69+
70+
- name: Test loading prebuilt
71+
shell: bash
72+
run: |
73+
source /opt/ros/${{ matrix.ros_distribution }}/setup.bash
74+
node -e "
75+
const rclnodejs = require('./index.js');
76+
console.log('Successfully loaded rclnodejs with prebuilt binary');
77+
console.log('Platform:', process.platform, 'Arch:', process.arch);
78+
console.log('ROS_DISTRO:', process.env.ROS_DISTRO);
79+
"

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,26 @@ npm i rclnodejs
5454
5555
See the [features](./docs/FEATURES.md) and try the [examples](https://github.com/RobotWebTools/rclnodejs/tree/develop/example) to get started.
5656

57+
### Prebuilt Binaries
58+
59+
rclnodejs ships with prebuilt native binaries for common Linux configurations since `v1.5.2`, eliminating the need for compilation during installation. This significantly speeds up installation and reduces dependencies.
60+
61+
**Supported Platforms:**
62+
63+
- **Ubuntu 22.04 (Jammy)** - ROS 2 Humble
64+
- **Ubuntu 24.04 (Noble)** - ROS 2 Jazzy, Kilted
65+
- **Architectures:** x64, arm64
66+
- **Node.js:** >= 16.20.2 (N-API compatible)
67+
68+
**Force Building from Source:**
69+
70+
If you need to build from source even when a prebuilt binary is available, set the environment variable:
71+
72+
```bash
73+
export RCLNODEJS_FORCE_BUILD=1
74+
npm install rclnodejs
75+
```
76+
5777
## rclnodejs-cli
5878

5979
[rclnodejs-cli](https://github.com/RobotWebTools/rclnodejs-cli/) is a companion project we recently launched to provide a commandline interface to a set of developer tools for working with this `rclnodejs`. You may find `rclnodejs-cli` particularly useful if you plan to create ROS 2 node(s) and launch files for working with multiple node orchestrations.

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const {
3737
} = require('./lib/parameter.js');
3838
const path = require('path');
3939
const QoS = require('./lib/qos.js');
40-
const rclnodejs = require('bindings')('rclnodejs');
40+
const rclnodejs = require('./lib/native_loader.js');
4141
const tsdGenerator = require('./rostsd_gen/index.js');
4242
const validator = require('./lib/validator.js');
4343
const Time = require('./lib/time.js');

lib/action/client.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
'use strict';
1616

17-
const rclnodejs = require('bindings')('rclnodejs');
17+
const rclnodejs = require('../native_loader.js');
1818
const ActionInterfaces = require('./interfaces.js');
1919
const ActionUuid = require('./uuid.js');
2020
const ClientGoalHandle = require('./client_goal_handle.js');

lib/action/graph.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
'use strict';
1616

17-
const rclnodejs = require('bindings')('rclnodejs');
17+
const rclnodejs = require('../native_loader.js');
1818

1919
/**
2020
* Get a list of action names and types for action clients associated with a node.

lib/action/server.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
'use strict';
1616

17-
const rclnodejs = require('bindings')('rclnodejs');
17+
const rclnodejs = require('../native_loader.js');
1818
const ActionInterfaces = require('./interfaces.js');
1919
const ActionUuid = require('./uuid.js');
2020
const DistroUtils = require('../distro.js');

lib/action/server_goal_handle.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
'use strict';
1616

17-
const rclnodejs = require('bindings')('rclnodejs');
17+
const rclnodejs = require('../native_loader.js');
1818
const ActionInterfaces = require('./interfaces.js');
1919
const Deferred = require('./deferred.js');
2020
const { GoalEvent } = require('./response.js');

lib/client.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
'use strict';
1616

17-
const rclnodejs = require('bindings')('rclnodejs');
17+
const rclnodejs = require('./native_loader.js');
1818
const DistroUtils = require('./distro.js');
1919
const Entity = require('./entity.js');
2020
const debug = require('debug')('rclnodejs:client');

lib/clock.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
'use strict';
1616

17-
const rclnodejs = require('bindings')('rclnodejs');
17+
const rclnodejs = require('./native_loader.js');
1818
const Time = require('./time.js');
1919
const ClockType = require('./clock_type.js');
2020

0 commit comments

Comments
 (0)