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

RobotWebTools / rclnodejs / 19690312781

26 Nov 2025 02:15AM UTC coverage: 82.843% (+1.1%) from 81.767%
19690312781

push

github

minggangw
Pump to 1.7.0 (#1329)

1074 of 1420 branches covered (75.63%)

Branch coverage included in aggregate %.

2446 of 2829 relevant lines covered (86.46%)

488.08 hits per line

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

47.83
/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 { execSync } = require('child_process');
26✔
20
const { NativeError } = require('./errors.js');
26✔
21
const bindings = require('bindings');
26✔
22
const debug = require('debug')('rclnodejs');
26✔
23
const { detectUbuntuCodename } = require('./utils');
26✔
24

25
let nativeModule = null;
26✔
26

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

36
  const rosDistro = process.env.ROS_DISTRO;
26✔
37
  const arch = process.arch;
26✔
38
  const ubuntuCodename = detectUbuntuCodename();
26✔
39

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

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

55
  if (!fs.existsSync(prebuildDir)) {
26!
56
    debug('No prebuilds directory found');
26✔
57
    return null;
26✔
58
  }
59

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

65
    if (fs.existsSync(exactMatchPath)) {
×
66
      debug(`Found exact match binary: ${exactMatchFilename}`);
×
67
      return require(exactMatchPath);
×
68
    }
69

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

76
  return null;
×
77
}
78

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

85
  // Environment variable to force building from source
86
  if (process.env.RCLNODEJS_FORCE_BUILD === '1') {
26!
87
    debug('Forcing build from source (RCLNODEJS_FORCE_BUILD=1)');
×
88

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

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

112
  const rosDistro = process.env.ROS_DISTRO;
26✔
113
  const ubuntuCodename = detectUbuntuCodename();
26✔
114

115
  debug(
26✔
116
    `Platform: ${process.platform}, Arch: ${process.arch}, Ubuntu: ${ubuntuCodename || 'unknown'}, ROS: ${rosDistro || 'unknown'}`
52!
117
  );
118

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

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

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

154
    // Trigger actual compilation
155
    try {
×
156
      debug('Running node-gyp rebuild...');
×
157
      execSync('npm run rebuild', {
×
158
        stdio: 'inherit',
159
        cwd: path.join(__dirname, '..'),
160
        timeout: 300000, // 5 minute timeout
161
      });
162

163
      // Try to load the newly built binary
164
      nativeModule = bindings('rclnodejs');
×
165
      debug('Successfully compiled and loaded from source');
×
166
      return nativeModule;
×
167
    } catch (compileError) {
168
      debug('Compilation failed:', compileError.message);
×
169
      throw new NativeError(
×
170
        `Failed to build rclnodejs from source: ${compileError.message}`,
171
        'Compilation',
172
        { cause: compileError }
173
      );
174
    }
175
  }
176
}
177

178
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