• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

RobotWebTools / rclnodejs / 18457503550

13 Oct 2025 06:48AM UTC coverage: 83.209% (-1.1%) from 84.306%
18457503550

Pull #1287

github

web-flow
Merge 72e5606da into d4d2d7c21
Pull Request #1287: Leverage prebuildify to provide prebuilt addon for npm package

802 of 1058 branches covered (75.8%)

Branch coverage included in aggregate %.

59 of 100 new or added lines in 25 files covered. (59.0%)

1978 of 2283 relevant lines covered (86.64%)

451.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.05
/lib/native_loader.js
1
// Copyright (c) 2025, The Robot Web Tools Contributors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
'use strict';
16

17
const fs = require('fs');
26✔
18
const path = require('path');
26✔
19
const debug = require('debug')('rclnodejs');
26✔
20
const { detectUbuntuCodename } = require('./utils');
26✔
21

22
let nativeModule = null;
26✔
23

24
// Simplified loader: only use prebuilt binaries with exact Ubuntu/ROS2/arch match
25
// Note: Prebuilt binaries are only supported on Linux (Ubuntu) platform
26
function customFallbackLoader() {
27
  // Prebuilt binaries are only for Linux platform
28
  if (process.platform !== 'linux') {
26!
NEW
29
    debug('Prebuilt binaries are only supported on Linux platform');
×
NEW
30
    return null;
×
31
  }
32

33
  const rosDistro = process.env.ROS_DISTRO;
26✔
34
  const arch = process.arch;
26✔
35
  const ubuntuCodename = detectUbuntuCodename();
26✔
36

37
  // Require all three components for exact match
38
  if (!rosDistro || !ubuntuCodename || !arch) {
26!
NEW
39
    debug(
×
40
      `Missing environment info - ROS: ${rosDistro}, Ubuntu: ${ubuntuCodename}, Arch: ${arch}`
41
    );
NEW
42
    return null;
×
43
  }
44

45
  const prebuildDir = path.join(
26✔
46
    __dirname,
47
    '..',
48
    'prebuilds',
49
    `${process.platform}-${arch}`
50
  );
51

52
  if (!fs.existsSync(prebuildDir)) {
26!
53
    debug('No prebuilds directory found');
26✔
54
    return null;
26✔
55
  }
56

NEW
57
  try {
×
58
    // Look for exact match binary: {ros_distro}-{ubuntu_codename}-{arch}-rclnodejs.node
NEW
59
    const exactMatchFilename = `${rosDistro}-${ubuntuCodename}-${arch}-rclnodejs.node`;
×
NEW
60
    const exactMatchPath = path.join(prebuildDir, exactMatchFilename);
×
61

NEW
62
    if (fs.existsSync(exactMatchPath)) {
×
NEW
63
      debug(`Found exact match binary: ${exactMatchFilename}`);
×
NEW
64
      return require(exactMatchPath);
×
65
    }
66

NEW
67
    debug(`No exact match found for: ${exactMatchFilename}`);
×
NEW
68
    return null;
×
69
  } catch (e) {
NEW
70
    debug('Error in simplified prebuilt loader:', e.message);
×
71
  }
72

NEW
73
  return null;
×
74
}
75

76
// Simplified prebuilt binary loader: exact match or build from source
77
function loadNativeAddon() {
78
  if (nativeModule) {
26!
NEW
79
    return nativeModule;
×
80
  }
81

82
  // Environment variable to force building from source
83
  if (process.env.RCLNODEJS_FORCE_BUILD === '1') {
26!
NEW
84
    debug('Forcing build from source (RCLNODEJS_FORCE_BUILD=1)');
×
85

86
    // Trigger actual compilation
NEW
87
    const { execSync } = require('child_process');
×
NEW
88
    try {
×
NEW
89
      debug('Running forced node-gyp rebuild...');
×
NEW
90
      execSync('npm run rebuild', {
×
91
        stdio: 'inherit',
92
        cwd: path.join(__dirname, '..'),
93
        timeout: 300000, // 5 minute timeout
94
      });
95

96
      // Load the newly built binary
NEW
97
      nativeModule = require('bindings')('rclnodejs');
×
NEW
98
      debug('Successfully force compiled and loaded from source');
×
NEW
99
      return nativeModule;
×
100
    } catch (compileError) {
NEW
101
      debug('Forced compilation failed:', compileError.message);
×
NEW
102
      throw new Error(
×
103
        `Failed to force build rclnodejs from source: ${compileError.message}`
104
      );
105
    }
106
  }
107

108
  const rosDistro = process.env.ROS_DISTRO;
26✔
109
  const ubuntuCodename = detectUbuntuCodename();
26✔
110

111
  debug(
26✔
112
    `Platform: ${process.platform}, Arch: ${process.arch}, Ubuntu: ${ubuntuCodename || 'unknown'}, ROS: ${rosDistro || 'unknown'}`
52!
113
  );
114

115
  // Prebuilt binaries are only supported on Linux (Ubuntu)
116
  if (process.platform === 'linux') {
26!
117
    // Try exact match prebuilt binary first
118
    try {
26✔
119
      const prebuiltModule = customFallbackLoader();
26✔
120
      if (prebuiltModule) {
26!
NEW
121
        nativeModule = prebuiltModule;
×
NEW
122
        return nativeModule;
×
123
      }
124
    } catch (e) {
NEW
125
      debug('Exact match prebuilt loading failed:', e.message);
×
126
    }
127

128
    debug(
26✔
129
      'No exact match prebuilt binary found, falling back to build from source'
130
    );
131
  } else {
NEW
132
    debug(
×
133
      `Platform ${process.platform} does not support prebuilt binaries, will try existing build or compile from source`
134
    );
135
  }
136

137
  try {
26✔
138
    // Try to find existing built binary first (works on all platforms)
139
    // The 'bindings' module will search standard locations like:
140
    // - build/Release/rclnodejs.node
141
    // - build/Debug/rclnodejs.node
142
    // - compiled/{node_version}/{platform}/{arch}/rclnodejs.node
143
    // etc.
144
    nativeModule = require('bindings')('rclnodejs');
26✔
145
    debug('Found and loaded existing built binary');
26✔
146
    return nativeModule;
26✔
147
  } catch {
NEW
148
    debug('No existing built binary found, triggering compilation...');
×
149

150
    // Trigger actual compilation
NEW
151
    const { execSync } = require('child_process');
×
NEW
152
    try {
×
NEW
153
      debug('Running node-gyp rebuild...');
×
NEW
154
      execSync('npm run rebuild', {
×
155
        stdio: 'inherit',
156
        cwd: path.join(__dirname, '..'),
157
        timeout: 300000, // 5 minute timeout
158
      });
159

160
      // Try to load the newly built binary
NEW
161
      nativeModule = require('bindings')('rclnodejs');
×
NEW
162
      debug('Successfully compiled and loaded from source');
×
NEW
163
      return nativeModule;
×
164
    } catch (compileError) {
NEW
165
      debug('Compilation failed:', compileError.message);
×
NEW
166
      throw new Error(
×
167
        `Failed to build rclnodejs from source: ${compileError.message}`
168
      );
169
    }
170
  }
171
}
172

173
module.exports = loadNativeAddon();
26✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc