Skip to content

fix: update gendef command in CMakeLists.txt for proper output redire… #139

fix: update gendef command in CMakeLists.txt for proper output redire…

fix: update gendef command in CMakeLists.txt for proper output redire… #139

Workflow file for this run

name: Build and Package
on:
push:
branches: [ main, develop ]
tags: [ 'v*' ]
pull_request:
branches: [ main ]
env:
NODE_VERSION: '20'
jobs:
build:
name: Build on ${{ matrix.os }} (${{ matrix.arch }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Linux builds
- os: ubuntu-latest
arch: x64
node_arch: x64
cmake_arch: x86_64
# Linux ARM64 builds (native)
- os: ubuntu-24.04-arm
arch: arm64
node_arch: arm64
cmake_arch: arm64
# macOS builds
- os: macos-latest
arch: arm64
node_arch: arm64
cmake_arch: arm64
# Windows builds with MSYS2/MinGW-w64
- os: windows-latest
arch: x64
node_arch: x64
cmake_arch: x64
steps:
# 1. 检出代码
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
# 2. 设置 Node.js 环境
- name: Setup Node.js
id: setup_node
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
architecture: ${{ matrix.node_arch }}
# 3. 安装系统依赖 - Linux
- name: Install Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
cmake \
build-essential \
gfortran \
libfftw3-dev \
libboost-all-dev \
pkg-config \
patchelf
# 3. 安装系统依赖 - macOS
- name: Install macOS dependencies
if: runner.os == 'macOS'
run: |
brew install cmake fftw boost gcc pkg-config dylibbundler
# 根据架构设置不同的路径
if [ "${{ matrix.arch }}" = "arm64" ]; then
# Apple Silicon (ARM64)
BREW_PREFIX="/opt/homebrew"
else
# Intel (x64)
BREW_PREFIX="/usr/local"
fi
# 确保brew路径在PATH中
echo "${BREW_PREFIX}/bin" >> $GITHUB_PATH
# 验证gfortran安装并设置环境变量
echo "Checking gfortran installation..."
ls -la ${BREW_PREFIX}/bin/gfortran* || echo "gfortran not found"
# 找到正确的gfortran路径并设置为环境变量
GFORTRAN_PATH=$(find ${BREW_PREFIX}/bin -name "gfortran*" | head -1)
if [ -n "$GFORTRAN_PATH" ] && [ -x "$GFORTRAN_PATH" ]; then
echo "Found gfortran at: $GFORTRAN_PATH"
echo "FC=$GFORTRAN_PATH" >> $GITHUB_ENV
echo "CMAKE_Fortran_COMPILER=$GFORTRAN_PATH" >> $GITHUB_ENV
# 测试gfortran
$GFORTRAN_PATH --version || echo "gfortran test failed"
else
echo "ERROR: gfortran not found or not executable"
exit 1
fi
# 设置库路径
echo "LIBRARY_PATH=${BREW_PREFIX}/lib:$LIBRARY_PATH" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=${BREW_PREFIX}/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV
# 3. 设置 MSYS2 环境 - Windows
- name: Setup MSYS2 (Windows)
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: >-
base-devel
mingw-w64-x86_64-toolchain
mingw-w64-x86_64-cmake
mingw-w64-x86_64-pkg-config
mingw-w64-x86_64-fftw
mingw-w64-x86_64-boost
mingw-w64-x86_64-gcc-fortran
mingw-w64-x86_64-nodejs
# 4. 安装 npm 依赖
- name: Install npm dependencies
run: npm ci --ignore-scripts
# 5. 构建 TypeScript
- name: Build TypeScript
run: npm run build:ts
# 6. 验证构建环境 - Windows
- name: Verify build environment (Windows MSYS2)
if: runner.os == 'Windows'
shell: msys2 {0}
run: |
echo "🔍 Verifying Windows MSYS2 build environment..."
# 验证必要工具
for tool in cmake gcc g++ gfortran pkg-config node npm npx; do
which $tool > /dev/null || { echo "❌ $tool not found"; exit 1; }
done
echo "✅ All build tools available"
# 验证依赖库
[ -f "node_modules/node-addon-api/napi.h" ] || { echo "❌ node-addon-api not found"; exit 1; }
pkg-config --exists fftw3f || { echo "❌ FFTW3F not found"; exit 1; }
[ -d "/mingw64/include/boost" ] || { echo "❌ Boost not found"; exit 1; }
echo "✅ All dependencies available"
# 7. 构建原生模块 - Linux/macOS
- name: Build native module (Linux/macOS)
if: runner.os != 'Windows'
run: |
# 清理可能存在的CMake缓存
rm -rf build/
# 原生编译(支持所有架构)
npx cmake-js compile --arch=${{ matrix.cmake_arch }}
# 8. 构建原生模块 - Windows MSYS2/MinGW-w64 (基于 build_mingw.sh)
- name: Build native module (Windows MSYS2)
if: runner.os == 'Windows'
shell: msys2 {0}
run: |
echo "=== Building with MSYS2/MinGW-w64 toolchain ==="
# 调试:检查关键DLL的存在
echo "🔍 Pre-build DLL availability check:"
for dll in libfftw3f-3.dll libfftw3f_threads-3.dll libgfortran-5.dll libgcc_s_seh-1.dll libwinpthread-1.dll libstdc++-6.dll; do
if [ -f "/mingw64/bin/$dll" ]; then
echo " ✅ $dll: $(stat -c%s /mingw64/bin/$dll) bytes"
else
echo " ❌ $dll: NOT FOUND"
fi
done
echo ""
# 设置环境变量强制使用 MinGW 工具链
export PKG_CONFIG_PATH="/mingw64/lib/pkgconfig"
export CMAKE_PREFIX_PATH="/mingw64"
export CC="gcc"
export CXX="g++"
export FC="gfortran"
export CMAKE_MAKE_PROGRAM="mingw32-make"
# 禁用 Visual Studio 检测
unset VSINSTALLDIR
unset VCINSTALLDIR
unset WindowsSDKDir
unset VCPKG_ROOT
echo -e "\n=== Environment variables ==="
echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH"
echo "CMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH"
echo "CC=$CC, CXX=$CXX, FC=$FC"
# 清理构建目录
rm -rf build/
echo -e "\n=== Starting build process ==="
npx cmake-js compile --arch=${{ matrix.cmake_arch }} \
--generator="MinGW Makefiles" \
--no-retry \
--verbose
BUILD_EXIT_CODE=$?
echo "Build exit code: $BUILD_EXIT_CODE"
if [ $BUILD_EXIT_CODE -ne 0 ]; then
echo "❌ Build failed with exit code $BUILD_EXIT_CODE"
exit $BUILD_EXIT_CODE
fi
# 验证构建产物
echo -e "\n=== Verifying build output ==="
if [ -f "build/Release/wsjtx_lib_nodejs.node" ]; then
echo "✅ Native module created: build/Release/wsjtx_lib_nodejs.node"
ls -lh build/Release/wsjtx_lib_nodejs.node
FILE_SIZE=$(stat -c%s "build/Release/wsjtx_lib_nodejs.node")
echo "File size: $FILE_SIZE bytes"
if [ "$FILE_SIZE" -lt 10000 ]; then
echo "❌ ERROR: Built file is too small ($FILE_SIZE bytes)!"
echo "This indicates a build failure that wasn't caught."
exit 1
fi
echo "File type:"
file build/Release/wsjtx_lib_nodejs.node || true
else
echo "❌ ERROR: Native module not found after build!"
echo "Build directory contents:"
find build -type f || true
exit 1
fi
# 10. 运行测试 - Linux/macOS
- name: Run tests (Linux/macOS)
if: runner.os != 'Windows'
run: |
echo "📁 Checking compiled files structure:"
ls -la dist/ || echo "dist directory not found"
find dist -name "*.js" -type f || echo "No JS files found in dist"
# 检查测试文件是否存在
if [ -f "dist/test/wsjtx.basic.test.js" ]; then
echo "✅ Basic test file found: dist/test/wsjtx.basic.test.js"
# 检查原生模块是否存在
if [ -f "build/Release/wsjtx_lib_nodejs.node" ]; then
echo "✅ Native module found: build/Release/wsjtx_lib_nodejs.node"
ls -la build/Release/wsjtx_lib_nodejs.node
# 运行基础测试
npm test
elif [ -f "build/wsjtx_lib_nodejs.node" ]; then
echo "✅ Native module found: build/wsjtx_lib_nodejs.node"
ls -la build/wsjtx_lib_nodejs.node
# 确保在正确位置,某些系统可能需要Release子目录
mkdir -p build/Release
cp build/wsjtx_lib_nodejs.node build/Release/
# 运行基础测试
npm test
else
echo "❌ Native module not found! Searching for .node files..."
find . -name "*.node" || echo "No .node files found"
exit 1
fi
else
echo "❌ Basic test file not found!"
echo "Available test files:"
find dist -name "*.test.js" -type f || echo "No test files found"
exit 1
fi
shell: bash
# 10a. 运行测试 - Windows (MSYS2/MinGW)
- name: Run tests (Windows)
if: runner.os == 'Windows'
shell: msys2 {0}
run: |
echo "📁 Checking test environment..."
# 检查测试文件
if [ ! -f "dist/test/wsjtx.basic.test.js" ]; then
echo "❌ Test file not found!"
find dist -name "*.test.js" -type f || echo "No test files found"
exit 1
fi
echo "✅ Test file: dist/test/wsjtx.basic.test.js"
# 检查原生模块是否存在
if [ ! -f "build/Release/wsjtx_lib_nodejs.node" ]; then
echo "❌ Native module not found at build/Release/"
echo "🔍 Searching for .node files..."
find . -name "*.node" -type f || echo "No .node files found"
exit 1
fi
# 验证原生模块文件
NODE_FILE="build/Release/wsjtx_lib_nodejs.node"
echo "✅ Native module found: $NODE_FILE"
# 检查文件大小
FILE_SIZE=$(stat -c%s "$NODE_FILE" 2>/dev/null || echo "0")
echo "📊 File size: $FILE_SIZE bytes"
if [ "$FILE_SIZE" -lt 10000 ]; then
echo "❌ ERROR: File size too small ($FILE_SIZE bytes), likely a build failure!"
echo "🔍 File details:"
ls -lh "$NODE_FILE"
echo "🔍 File type:"
file "$NODE_FILE" || true
echo "🔍 Checking build log for errors..."
exit 1
fi
# 检查文件类型
echo "🔍 File type check:"
file "$NODE_FILE" || true
# 检查 DLL 依赖
echo ""
echo "🔍 DLL dependencies:"
objdump -p "$NODE_FILE" | grep "DLL Name" || echo "Cannot check DLL dependencies"
# 设置库路径
echo ""
echo "🔧 Setting up environment..."
export PATH="/mingw64/bin:$PATH"
export LD_LIBRARY_PATH="/mingw64/lib:$LD_LIBRARY_PATH"
# 验证关键 DLL 是否存在
echo "🔍 Checking critical DLLs..."
for dll in libfftw3f-3.dll libgfortran-5.dll libgcc_s_seh-1.dll; do
if [ -f "/mingw64/bin/$dll" ]; then
echo " ✅ $dll"
else
echo " ❌ $dll NOT FOUND"
fi
done
# 运行测试
echo ""
echo "🧪 Running tests..."
if npm test; then
echo "✅ Tests passed!"
else
echo "❌ Test failed"
echo "🔍 Attempting direct module load..."
node -e "try { require('./build/Release/wsjtx_lib_nodejs.node'); console.log('✅ Module loads OK'); } catch(e) { console.error('❌ Error:', e.message); console.error('Stack:', e.stack); }"
exit 1
fi
# 11. 创建预构建二进制文件 - Linux/macOS
- name: Create prebuilt binaries (Linux/macOS)
if: runner.os != 'Windows'
run: |
# 加载辅助函数
source scripts/ci-helpers.sh
# 获取平台名称
PLATFORM_NAME=$(get_platform_name "${{ matrix.os }}")
TARGET_DIR="prebuilds/$PLATFORM_NAME-${{ matrix.arch }}"
echo "========================================="
echo "📦 Creating prebuilt package"
echo "========================================="
echo "Platform: $PLATFORM_NAME"
echo "Architecture: ${{ matrix.arch }}"
echo "Target: $TARGET_DIR"
echo "========================================="
mkdir -p "$TARGET_DIR"
# 复制 .node 文件
if [ ! -f "build/Release/wsjtx_lib_nodejs.node" ]; then
echo "❌ Native module not found at build/Release/"
find build -maxdepth 2 -name "*.node" -type f
exit 1
fi
cp build/Release/wsjtx_lib_nodejs.node "$TARGET_DIR/"
NODE_FILE="$TARGET_DIR/wsjtx_lib_nodejs.node"
echo "✅ Copied .node file to $TARGET_DIR"
# 平台特定的依赖打包
if [ "${{ runner.os }}" = "Linux" ]; then
bundle_linux_dependencies "$NODE_FILE" "$TARGET_DIR"
elif [ "${{ runner.os }}" = "macOS" ]; then
bundle_macos_dependencies "$NODE_FILE" "$TARGET_DIR"
fi
# 显示结果
show_package_summary "$TARGET_DIR"
# 创建构建信息
create_build_info "$TARGET_DIR" "$PLATFORM_NAME" "${{ matrix.os }}" "${{ matrix.arch }}" "${{ env.NODE_VERSION }}" "${{ matrix.cmake_arch }}"
shell: bash
# 11a. 创建预构建二进制文件 - Windows (MSYS2)
- name: Create prebuilt binaries (Windows)
if: runner.os == 'Windows'
shell: msys2 {0}
run: |
# 加载辅助函数
source scripts/ci-helpers.sh
# 获取平台名称
PLATFORM_NAME=$(get_platform_name "${{ matrix.os }}")
TARGET_DIR="prebuilds/$PLATFORM_NAME-${{ matrix.arch }}"
echo "========================================="
echo "📦 Creating prebuilt package (Windows)"
echo "========================================="
echo "Platform: $PLATFORM_NAME"
echo "Architecture: ${{ matrix.arch }}"
echo "Target: $TARGET_DIR"
echo "========================================="
mkdir -p "$TARGET_DIR"
# 复制 .node 文件
if [ -f "build/Release/wsjtx_lib_nodejs.node" ]; then
cp build/Release/wsjtx_lib_nodejs.node "$TARGET_DIR/"
NODE_FILE="build/Release/wsjtx_lib_nodejs.node"
elif [ -f "build/wsjtx_lib_nodejs.node" ]; then
cp build/wsjtx_lib_nodejs.node "$TARGET_DIR/"
NODE_FILE="build/wsjtx_lib_nodejs.node"
else
echo "❌ Native module not found!"
exit 1
fi
echo "✅ Copied .node file to $TARGET_DIR"
# 打包 DLL 依赖
bundle_windows_dependencies "$NODE_FILE" "$TARGET_DIR"
# 显示结果
show_package_summary "$TARGET_DIR"
# 创建构建信息
create_build_info "$TARGET_DIR" "$PLATFORM_NAME" "${{ matrix.os }}" "${{ matrix.arch }}" "${{ env.NODE_VERSION }}" "${{ matrix.cmake_arch }}"
# 12. 上传构建产物到 artifacts
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: prebuilt-${{ matrix.os == 'ubuntu-24.04-arm' && 'linux' || (matrix.os == 'ubuntu-latest' && 'linux' || (matrix.os == 'macos-latest' && 'darwin' || 'win32')) }}-${{ matrix.arch }}
path: prebuilds/
retention-days: 30
if-no-files-found: error
# 13. 上传完整构建目录(用于调试)
- name: Upload build directory for debugging
if: failure()
uses: actions/upload-artifact@v4
with:
name: build-debug-${{ matrix.os == 'ubuntu-24.04-arm' && 'linux' || (matrix.os == 'ubuntu-latest' && 'linux' || (matrix.os == 'macos-latest' && 'darwin' || 'win32')) }}-${{ matrix.arch }}
path: |
build/
CMakeCache.txt
cmake_install.cmake
retention-days: 7
# 汇总所有构建产物
collect-artifacts:
name: Collect All Artifacts
needs: build
runs-on: ubuntu-latest
if: always() && needs.build.result == 'success'
steps:
- name: Download all build artifacts
uses: actions/download-artifact@v4
with:
path: all-artifacts
- name: Organize artifacts
run: |
mkdir -p final-prebuilds
# 合并所有预构建文件
echo "📁 可用的构建产物目录:"
ls -la all-artifacts/ || echo "No artifacts directory"
for artifact_dir in all-artifacts/prebuilt-*; do
if [ -d "$artifact_dir" ]; then
echo "📦 处理 $artifact_dir"
# 显示目录内容以便调试
echo " 内容:"
ls -la "$artifact_dir"
cp -r "$artifact_dir"/* final-prebuilds/
fi
done
echo ""
echo "📋 合并后的final-prebuilds目录结构:"
find final-prebuilds -type f | sort
# 显示最终结果
echo "所有平台的构建产物:"
find final-prebuilds -name "*.node" -exec ls -la {} \;
# 汇总构建信息
echo "# 构建摘要" > build-summary.md
echo "构建时间: $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> build-summary.md
echo "" >> build-summary.md
echo "## 支持的平台:" >> build-summary.md
for info_file in final-prebuilds/*/build-info.json; do
if [ -f "$info_file" ]; then
platform=$(jq -r '.platform' "$info_file")
arch=$(jq -r '.arch' "$info_file")
file_size=$(jq -r '.file_size' "$info_file")
echo "- $platform-$arch ($(numfmt --to=iec $file_size 2>/dev/null || echo $file_size))" >> build-summary.md
fi
done
echo "" >> build-summary.md
echo "## 文件详情:" >> build-summary.md
find final-prebuilds -name "*.node" | while read file; do
size=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null || echo "unknown")
size_human=$(numfmt --to=iec $size 2>/dev/null || echo "$size bytes")
echo "- \`$(basename "$file")\`: $size_human" >> build-summary.md
done
- name: Upload combined artifacts
uses: actions/upload-artifact@v4
with:
name: all-prebuilds
path: |
final-prebuilds/
build-summary.md
retention-days: 90