CtrlK
BlogDocsLog inGet started
Tessl Logo

mcollina/nodejs-core

Debugs native module crashes, optimizes V8 performance, configures node-gyp builds, writes N-API/node-addon-api bindings, and diagnoses libuv event loop issues in Node.js. Use when working with C++ addons, native modules, binding.gyp, node-gyp errors, segfaults, memory leaks in native code, V8 optimization/deoptimization, libuv thread pool tuning, N-API or NAN bindings, build system failures, or any Node.js internals below the JavaScript layer.

99

Quality

99%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

build-system.mdrules/

name:
build-system
description:
gyp, ninja, make, cross-platform compilation for Node.js
metadata:
{"tags":"build, gyp, ninja, make, compilation, cross-platform"}

Node.js Build System

Understanding the Node.js build system is essential for building from source, debugging build issues, and developing native addons.

Build System Overview

Source Code
     │
     ▼
configure (Python)     ←── Detects platform, creates config
     │
     ▼
GYP (generate-your-project)  ←── Creates platform-specific build files
     │
     ├──> Makefile (Linux/macOS)
     ├──> Ninja files
     └──> MSBuild (Windows)
            │
            ▼
     Compiler (gcc/clang/MSVC)
            │
            ▼
     Node.js binary

Building Node.js from Source

Prerequisites

# Ubuntu/Debian
sudo apt-get install -y \
  build-essential \
  python3 \
  g++ \
  make \
  ninja-build

# macOS
xcode-select --install

# Windows
# Install Visual Studio 2022 with C++ workload
# Install Python 3

Basic Build

# Clone repository
git clone https://github.com/nodejs/node.git
cd node

# Configure
./configure

# Build (uses all cores)
make -j$(nproc)

# Or with ninja (faster)
./configure --ninja
ninja -C out/Release

# Test
./node -v
make test

Build Options

# Debug build
./configure --debug
make -j$(nproc)

# Release build (default)
./configure
make -j$(nproc)

# With shared library
./configure --shared

# Custom install prefix
./configure --prefix=/opt/node

# Without npm
./configure --without-npm

# Without ICU (smaller binary)
./configure --without-intl

# With OpenSSL from system
./configure --shared-openssl

# Cross-compile for different architecture
./configure --dest-cpu=arm64 --dest-os=linux

GYP (Generate Your Project)

binding.gyp Structure

{
  "targets": [
    {
      "target_name": "addon",
      "sources": ["src/addon.cc"],
      "include_dirs": [
        "<!@(node -p \"require('node-addon-api').include\")"
      ],
      "defines": ["NAPI_VERSION=8"],
      "cflags!": ["-fno-exceptions"],
      "cflags_cc!": ["-fno-exceptions"],
      "conditions": [
        ["OS=='win'", {
          "defines": ["_HAS_EXCEPTIONS=1"],
          "msvs_settings": {
            "VCCLCompilerTool": {
              "ExceptionHandling": 1
            }
          }
        }],
        ["OS=='mac'", {
          "xcode_settings": {
            "GCC_ENABLE_CPP_EXCEPTIONS": "YES",
            "CLANG_CXX_LIBRARY": "libc++",
            "MACOSX_DEPLOYMENT_TARGET": "10.15"
          }
        }]
      ],
      "dependencies": [
        "<!(node -p \"require('node-addon-api').gyp\")"
      ]
    }
  ]
}

GYP Variables

{
  "variables": {
    "myvar": "default_value",
    "othervar%": "value_if_not_set"  # % means "set if not defined"
  },
  "targets": [{
    "target_name": "addon",
    "defines": ["MY_VAR=<(myvar)"]  # Use variable
  }]
}

Conditional Compilation

{
  "conditions": [
    # OS conditions
    ["OS=='linux'", {
      "sources": ["src/linux.cc"],
      "libraries": ["-lpthread"]
    }],
    ["OS=='mac'", {
      "sources": ["src/mac.cc"],
      "libraries": ["-framework CoreFoundation"]
    }],
    ["OS=='win'", {
      "sources": ["src/win.cc"],
      "libraries": ["ws2_32.lib"]
    }],

    # Architecture conditions
    ["target_arch=='x64'", {
      "defines": ["IS_64BIT"]
    }],

    # Node version conditions
    ["node_major_version >= 18", {
      "defines": ["HAS_NEW_FEATURE"]
    }]
  ]
}

node-gyp

Installation and Usage

# Install globally
npm install -g node-gyp

# Configure (generates build files)
node-gyp configure

# Build
node-gyp build

# Rebuild (clean + configure + build)
node-gyp rebuild

# Clean
node-gyp clean

# Debug build
node-gyp configure --debug
node-gyp build --debug

Common node-gyp Issues

# Python not found
npm config set python /usr/bin/python3
# Or set environment variable
export PYTHON=/usr/bin/python3

# Visual Studio not found (Windows)
npm config set msvs_version 2022

# Specify Node.js headers location
node-gyp rebuild --nodedir=/path/to/node

# Download headers manually
node-gyp install

CMake.js Alternative

For projects preferring CMake:

npm install cmake-js --save-dev
# CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(addon)

include_directories(${CMAKE_JS_INC})

add_library(${PROJECT_NAME} SHARED
  src/addon.cpp
)

set_target_properties(${PROJECT_NAME} PROPERTIES
  PREFIX ""
  SUFFIX ".node"
)

target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})

Cross-Compilation

Building for Different Architectures

# ARM64 on x64 host
./configure \
  --dest-cpu=arm64 \
  --dest-os=linux \
  --cross-compiling

make -j$(nproc)

Docker Cross-Compile

FROM dockcross/linux-arm64

RUN apt-get update && apt-get install -y python3

WORKDIR /src
COPY . .

RUN ./configure --dest-cpu=arm64 --dest-os=linux
RUN make -j$(nproc)

Native Addons Cross-Compile

# Set target architecture
npm config set target_arch arm64

# Set Node.js headers
npm config set nodedir /path/to/node-arm64

# Rebuild all native addons
npm rebuild

Build Debugging

Verbose Build

# Make with verbose output
make V=1

# node-gyp verbose
node-gyp rebuild --verbose

# Very verbose
node-gyp rebuild --loglevel=silly

Common Build Errors

# Missing Python
# Solution: Install Python 3 and set path
export PYTHON=/usr/bin/python3

# Missing compiler
# Solution: Install build tools
# Ubuntu: apt install build-essential
# macOS: xcode-select --install

# Header not found
# Example: fatal error: node.h: No such file or directory
# Solution: Install Node.js development headers
node-gyp install

# Symbol not found (linking)
# Example: undefined reference to `symbol_name'
# Check: Library order, missing dependencies
# Solution: Add to "libraries" in binding.gyp

# ABI mismatch
# Example: "Module version mismatch"
# Solution: Rebuild for current Node.js version
npm rebuild

Build with Debug Symbols

# binding.gyp
{
  "targets": [{
    "target_name": "addon",
    "sources": ["src/addon.cc"],
    "cflags": ["-g", "-O0"],
    "cflags_cc": ["-g", "-O0"],
    "xcode_settings": {
      "GCC_OPTIMIZATION_LEVEL": "0",
      "GCC_GENERATE_DEBUGGING_SYMBOLS": "YES"
    },
    "msvs_settings": {
      "VCCLCompilerTool": {
        "Optimization": 0,
        "DebugInformationFormat": 3
      }
    }
  }]
}

Ninja Build

Ninja is faster than Make for incremental builds:

# Configure with Ninja
./configure --ninja

# Build
ninja -C out/Release

# Build specific target
ninja -C out/Release node

# Verbose
ninja -C out/Release -v

# Clean
ninja -C out/Release -t clean

Static Analysis

Linting

# Node.js core linting
make lint
make lint-cpp
make lint-js

# For addons, use clang-tidy
clang-tidy src/*.cc -- -I$(node -p "require('node-addon-api').include")

Address Sanitizer

# Build Node.js with ASan
./configure --debug --enable-asan
make -j$(nproc)

# Or for addons
node-gyp rebuild --debug
ASAN_OPTIONS=detect_leaks=1 node test.js

Prebuild Binaries

prebuildify

npm install prebuildify --save-dev
{
  "scripts": {
    "prebuild": "prebuildify --napi --strip",
    "prebuild-cross": "prebuildify-cross -i centos7 -i alpine"
  }
}

node-pre-gyp

{
  "binary": {
    "module_name": "addon",
    "module_path": "./lib/binding/{platform}-{arch}",
    "host": "https://github.com/user/repo/releases/download/",
    "remote_path": "v{version}",
    "package_name": "{module_name}-v{version}-{platform}-{arch}.tar.gz"
  }
}

Platform-Specific Notes

Linux

# Use specific GCC version
export CC=gcc-11
export CXX=g++-11
./configure

# Static linking
./configure --fully-static

macOS

# Universal binary (Intel + Apple Silicon)
./configure --dest-cpu=arm64
make -j$(nproc)
mv out/Release/node node-arm64

./configure --dest-cpu=x64
make -j$(nproc)
mv out/Release/node node-x64

lipo -create -output node node-arm64 node-x64

Windows

# Use specific Visual Studio version
.\vcbuild.bat vs2022

# Build 64-bit
.\vcbuild.bat x64

# Release build
.\vcbuild.bat release

# Debug build
.\vcbuild.bat debug

References

  • Node.js Building: https://github.com/nodejs/node/blob/main/BUILDING.md
  • GYP documentation: https://gyp.gsrc.io/docs/UserDocumentation.md
  • node-gyp: https://github.com/nodejs/node-gyp
  • prebuildify: https://github.com/prebuild/prebuildify

rules

build-system.md

child-process-internals.md

commit-messages.md

contributing.md

crypto-internals.md

debugging-native.md

fs-internals.md

libuv-async-io.md

libuv-event-loop.md

libuv-thread-pool.md

memory-debugging.md

napi.md

native-memory.md

net-internals.md

node-addon-api.md

profiling-v8.md

streams-internals.md

v8-garbage-collection.md

v8-hidden-classes.md

v8-jit-compilation.md

worker-threads-internals.md

SKILL.md

tile.json