Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 49 additions & 10 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,65 @@ on:

jobs:
build:
runs-on: ubuntu-latest
name: Build & test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
permissions:
contents: read
# Hard backstop so a hung step/process never consumes the full 6-hour CI
# ceiling (seen on windows-latest before the CI guard was added).
timeout-minutes: 30

strategy:
fail-fast: false
matrix:
# Exercise the platforms INSTALL.md documents: Linux, macOS, Windows.
os: [ubuntu-latest, macos-latest, windows-latest]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y g++ make
- name: Install CMake (Linux)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y cmake

# CMake is preinstalled on the GitHub Actions macOS and Windows runners.

- name: Configure
run: cmake -B build -S . -DCMAKE_BUILD_TYPE=Release

- name: Build
run: make -j$(nproc)
run: cmake --build build --config Release -j$(nproc) 2>/dev/null || cmake --build build --config Release -j2
shell: bash

- name: Run unit tests
run: make test
run: ctest --test-dir build --build-config Release --output-on-failure --timeout 300
shell: bash

- name: Simulation smoke test
shell: bash
run: |
BIN="build/src/nec2++"
[ -f "$BIN" ] || BIN="build/src/Release/nec2++.exe"
[ -f "$BIN" ] || BIN="build/src/nec2++.exe"
"$BIN" -i testharness/data/herzian_dipole.nec -o smoke_output.txt
grep -q "TOTAL RUN TIME" smoke_output.txt && echo "Smoke test passed"

# Separate job: the WASM build (needs Docker, so Linux only).
wasm:
name: WASM build
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Build WASM via Emscripten Docker image
run: ./scripts/build_wasm_docker.sh

- name: Run simulation smoke test
- name: Verify WASM artifacts
run: |
./nec2++ -i testharness/data/herzian_dipole.nec -o /tmp/nec2_test_output.txt
grep -q "TOTAL RUN TIME" /tmp/nec2_test_output.txt && echo "Smoke test passed"
test -f nec2pp.js
test -f nec2pp.wasm
echo "WASM artifacts present: $(ls -la nec2pp.js nec2pp.wasm)"
36 changes: 31 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,41 @@
*.exe
*.so
*.o
*.a
*.la
*.trs
src/nec2++
src/nec2diff
src/test_manager
src/necpp_test
/nec2++
/nec2diff
build/
nec2pp.js
nec2pp.wasm
# Legacy test binary name (pre-CMake era); kept ignored in case of stale trees.
src/necpp_test
src/test_manager

# CMake build artifacts #
#########################
build/
build-*/
build-wasm/
build-wasm-test/
CMakeFiles/
cmake_install.cmake
CMakeCache.txt
CMakeError.log
CMakeOutput.log
install_manifest.txt
_CPack_Packages/
# CMake-generated build-system files inside source dirs (e.g. src/Makefile
# produced by `cmake -B src`). Keep hand-written Makefiles in antlr/,
# testharness/, example/ — they are not generated.
src/Makefile


# ANTLR generated artifacts (built in Docker) #
###############################################
antlr/generated/
antlr/nec_parse
antlr/build/

# Packages #
############
Expand All @@ -30,6 +54,8 @@ nec2pp.wasm
*.rar
*.tar
*.zip
*.deb
*.rpm

# Logs and databases #
######################
Expand Down
120 changes: 120 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#####################################################################################
#
# CMake build for nec2++ — replaces the hand-written Makefile.
#
# Copyright (C) 2004-2025 Timothy C.A. Molteno
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
#####################################################################################

cmake_minimum_required(VERSION 3.16)

project(necpp
VERSION 2.1.1
DESCRIPTION "NEC2++ antenna modelling library and tools"
HOMEPAGE_URL "https://github.com/tmolteno/necpp"
LANGUAGES CXX)

# --- C++ standard ----------------------------------------------------------
# C++17 is required by the codebase (structured bindings, etc.).
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Default to a Release-flavoured build when the caller did not pick one.
# Multi-config generators (Visual Studio, Xcode) choose per-config instead.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()

# Position-independent code so the same objects can back the shared library
# and be linked into executables on platforms that require it.
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# Build date stamped into the version string written to config.h.
string(TIMESTAMP NECPP_BUILD_DATE "%Y-%m-%d")

# --- Options ---------------------------------------------------------------
option(NECPP_BUILD_TESTS "Build the Catch2 unit tests" ON)
option(NECPP_BUILD_WASM "Build the Emscripten/WASM target (needs emcc)" OFF)
option(NECPP_BUILD_DOCS "Build the Doxygen documentation" OFF)
option(BUILD_SHARED_LIBS "Also build a shared libnecpp in addition to the static one" ON)

# Bundled Eigen is always used; there is no external-Eigen path.
set(NECPP_EIGEN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/eigen)

# The codebase uses standard C functions (strncpy, fopen, sprintf, ...) that
# are intentionally safe in their call sites here. MSVC deprecates them in
# favor of the _s variants; silence the C4996 noise project-wide on MSVC.
if(MSVC)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif()

# Generate config.h from the template. Output lives in ${CMAKE_BINARY_DIR}
# and is put on the include path by every target that needs it.
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in
${CMAKE_BINARY_DIR}/config.h
@ONLY)

add_subdirectory(src)

if(NECPP_BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()

# --- pkg-config file -------------------------------------------------------
# Generated alongside the build so downstream users of `pkg-config --cflags
# --libs necpp` have a path to query. Installed by src/CMakeLists.txt.
include(InstallRequiredSystemLibraries)

# --- CPack -----------------------------------------------------------------
# Replaces the stale debian/ packaging. Produces .deb, .rpm, and .tar.xz.
include(CPackComponent)

set(CPACK_PACKAGE_NAME "necpp")
set(CPACK_PACKAGE_VENDOR "Timothy C.A. Molteno")
set(CPACK_PACKAGE_CONTACT "tim@molteno.net")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "NEC2++ antenna modelling system")
set(CPACK_PACKAGE_DESCRIPTION "NEC2++ (Numerical Electromagnetics Code) is software for modelling antennas using the Method of Moments. It is a complete rewrite of the original NEC-2 FORTRAN software developed by Lawrence Livermore Laboratories.")
set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/tmolteno/necpp")
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/COPYING)
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})

# Split the install into runtime (lib), development (headers), and CLI
# components so packagers can ship libnecpp / necpp-dev / necpp separately.
# Note: no GROUP here — putting components in a GROUP makes CPack merge them
# into a single group-named package on DEB/RPM, which defeats the split.
cpack_add_component(Runtime
DISPLAY_NAME "nec2++ runtime library"
DESCRIPTION "Shared library libnecpp.so for running programs built against nec2++.")
cpack_add_component(Development
DISPLAY_NAME "development files"
DESCRIPTION "Static library, headers, pkg-config and CMake package files for compiling applications against nec2++.")
cpack_add_component(CLI
DISPLAY_NAME "nec2++ command-line tools"
DESCRIPTION "The nec2++ and nec2diff command-line programs.")

# Debian-specific knobs.
set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_CONTACT})
set(CPACK_DEBIAN_RUNTIME_PACKAGE_NAME "libnecpp${PROJECT_VERSION_MAJOR}")
set(CPACK_DEBIAN_DEVELOPMENT_PACKAGE_NAME "libnecpp-dev")
set(CPACK_DEBIAN_CLI_PACKAGE_NAME "necpp")
set(CPACK_DEB_COMPONENT_INSTALL ON)

# RPM-specific knobs.
set(CPACK_RPM_PACKAGE_LICENSE "GPL-2.0-or-later")
set(CPACK_RPM_RUNTIME_PACKAGE_NAME "libnecpp${PROJECT_VERSION_MAJOR}")
set(CPACK_RPM_DEVELOPMENT_PACKAGE_NAME "libnecpp-devel")
set(CPACK_RPM_CLI_PACKAGE_NAME "necpp")
set(CPACK_RPM_COMPONENT_INSTALL ON)

include(CPack)
Loading
Loading