I am working on an Electron project with node-api (for C++ addons). The app crashes, even after a full-build. The problem that I am facing occurs within the C++ template addon that I have made.
I have added extensive logging in order to figure out where the error occurs, and narrowed it down to the helloFunc = Napi::Function::New(env, HelloWorld); call within [addon.cpp] (because the "Creating helloFunc..." log appears in the terminal, but the "Created helloFunc." log doesn't).
However, the try/catch blocks that I added around this line aren't logging anything, so I assume some memory access error is occuring at the OS-level, and the Napi::Object Init function is abruptly ending at the relevant line, so all later lines containing the std::cout logs aren't running.
In regards to this, my question is: Why is the line `Napi::Function::New(env, HelloWorld)` even causing a memory access error?
Any answer that explains either (a) the detailed debugging steps for my case or (b) the origin of the error within the code suffices. I don't need both points to be delved into. The replier can decide which one he finds more useful to me - I myself just don't know, and I don't want to choose the wrong answer format and leave with useless information.
In a previous iteration of this question, it was suggested to me that I "use a debugger" to figure out what is going wrong. In regards to this suggestion, I must say: That's exactly what I tried to do using C++ logs! But since the error seems to not be handled by the C++, doing so tells me nothing about the error. And I have no clue how to debug at a lower level in this scenario, which ties into my question.
All relevant files in my project are below:
[addon.cpp]
#include <napi.h>
#include <iostream>
Napi::String HelloWorld(const Napi::CallbackInfo& info) {
std::cout << "[C++] " << "Getting environment..." << std::endl; // Is not run
Napi::Env env = info.Env();
std::string helloWorld = "Hello from C++!";
return Napi::String::New(env, helloWorld);
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
Napi::Function helloFunc;
try {
std::cout << "[C++] " << "Creating helloFunc..." << std::endl;
helloFunc = Napi::Function::New(env, HelloWorld);
std::cout << "[C++] " << "Created helloFunc." << std::endl;
} catch (...) {
}
exports.Set("hello", helloFunc);
return exports;
}
NODE_API_MODULE(addon, Init)
[CMakeLists.txt]
cmake_minimum_required(VERSION 3.15)
project(my_native_addon)
execute_process(
COMMAND node -p "require('path').dirname(require.resolve('node-addon-api'))"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE NODE_ADDON_API_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
include_directories(${NODE_ADDON_API_DIR})
include_directories(${CMAKE_JS_INC})
# Enable C++ exceptions for node-addon-api
add_definitions(-DNAPI_CPP_EXCEPTIONS)
# Enable C++ exception handling
if(MSVC)
add_compile_options(/EHsc)
else()
add_compile_options(-fexceptions)
endif()
# Set source files
set(CMAKE_JS_SRC "native/addon.cpp")
# Build the library
add_library(${PROJECT_NAME} SHARED ${CMAKE_JS_SRC})
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})
[package.json]
{
"scripts": {
"ng": "ng",
"build": "ng build",
"build-native": "cmake-js rebuild --runtime=electron --runtime-version=40.6.1",
"build-angular": "ng build --base-href ./",
"start-electron": "electron electron/main.js",
"full-build": "npm run build-native && npm run build-angular && npm run start-electron"
},
"packageManager": "[email protected]",
"dependencies": {
"node-addon-api": "^8.5.0",
},
"devDependencies": {
"@electron/rebuild": "^4.0.3",
"cmake-js": "^8.0.0",
"electron": "40.6.1",
"electron-builder": "^26.8.1",
}
}
[main.js]
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
console.log("Starting Electron App...");
let addon;
const addonPath = path.join(__dirname, '../build/Release/my_native_addon.node');
addon = require(addonPath);
console.log("Native addon loaded successfully!");
try {
app.whenReady().then(() => {
ipcMain.handle('get-hello-message', () => {
if (addon) {
return addon.hello();
}
return "Addon not loaded";
});
})
} catch (err) {
console.error("Failed to start Electron app:", err);
}