Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4cc95f8
add nanoclr posix
Ellerbach Apr 14, 2026
31e637e
Code style fixes for nanoframework/nf-interpreter PR#3313 (#3314)
nfbot Apr 15, 2026
20e1127
Update src/CLR/Include/nanoCLR_Hardware.h
Ellerbach Apr 15, 2026
9cfd3d6
some changes on PR feedback
Ellerbach Apr 15, 2026
7b5b411
more changes
Ellerbach Apr 15, 2026
81bb833
fix linux pipeline
Ellerbach Apr 15, 2026
ed98944
Code style fixes for nanoframework/nf-interpreter PR#3313 (#3318)
nfbot Apr 15, 2026
24c3e54
fixibng build
Ellerbach Apr 15, 2026
44df935
more chqnges
Ellerbach Apr 15, 2026
d3a4964
more changes
Ellerbach Apr 15, 2026
889f720
fixing serial port warning and linux build
Ellerbach Apr 15, 2026
fc99cf3
Code style fixes for nanoframework/nf-interpreter PR#3313 (#3320)
nfbot Apr 15, 2026
77e9b2c
fixing linux build, hopefully for real
Ellerbach Apr 15, 2026
5334e7f
trying to fix the zin dll build
Ellerbach Apr 15, 2026
55b091e
revert Thread.cpp to main - debug print block used uninitialized hr c…
Ellerbach Apr 15, 2026
4bb6fc1
latest small fixes
Ellerbach Apr 15, 2026
194468c
Merge branch 'main' into fix-nanoclr-update
Ellerbach Apr 15, 2026
8e6830f
Code style fixes for nanoframework/nf-interpreter PR#3313 (#3323)
nfbot Apr 15, 2026
9e54c14
adjusting for building everything and packaging everything properly
Ellerbach Apr 15, 2026
8139a5f
fix: guard smoke-run for cross-compiled POSIX legs
Ellerbach Apr 15, 2026
3fdd33e
fix: use macOS-latest runner for osx-x64 cross-compile leg
Ellerbach Apr 15, 2026
374c747
fix: cross-compile linux-arm64 on ubuntu-22.04 x64 runner
Ellerbach Apr 15, 2026
7e204c4
chore: publish nupkg as pipeline artifact for inspection
Ellerbach Apr 15, 2026
bcfc304
fix: use TargetFramework for native lib PackagePath in nupkg
Ellerbach Apr 16, 2026
d9d0096
fix: probe portable RID fallback in NativeNanoClrLoader
Ellerbach Apr 16, 2026
78249c6
fixing encoding
Ellerbach Apr 16, 2026
fb342ec
last fix
Ellerbach Apr 16, 2026
4a43e01
adjusting pal time for linux
Ellerbach Apr 16, 2026
591ca49
attempt to fix linux run issues
Ellerbach Apr 16, 2026
61ec205
debug for linux
Ellerbach Apr 16, 2026
d2f0694
timing fix for linux execution
Ellerbach Apr 17, 2026
82477e0
reverting
Ellerbach Apr 17, 2026
f349f9a
fixing linuxfixing properly linux timing
Ellerbach Apr 17, 2026
db7b19e
fix git mess
Ellerbach Apr 17, 2026
27508fe
fixing posix for real this time, yeah!
Ellerbach Apr 17, 2026
5fcb759
more linux fixes
Ellerbach Apr 17, 2026
efea4e0
more fixes from PR review and cleaning
Ellerbach Apr 17, 2026
94db178
Merge branch 'main' into fix-nanoclr-update
Ellerbach Apr 17, 2026
b1fb84c
Merge branch 'main' into fix-nanoclr-update
Ellerbach Apr 21, 2026
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
81 changes: 81 additions & 0 deletions .github/workflows/posix-nanoclr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: posix-nanoclr

on:
push:
paths:
- "targets/posix/**"
- "src/CLR/**"
- "src/HAL/**"
- "src/PAL/**"
- ".github/workflows/posix-nanoclr.yml"
pull_request:
paths:
- "targets/posix/**"
- "src/CLR/**"
- "src/HAL/**"
- "src/PAL/**"
- ".github/workflows/posix-nanoclr.yml"

jobs:
build-posix-nanoclr:
strategy:
matrix:
include:
- os: macos-14
label: macOS
- os: ubuntu-22.04
label: Linux
fail-fast: false

runs-on: ${{ matrix.os }}
name: Build (${{ matrix.label }})

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

- name: Install Ninja (if missing)
run: |
if ! command -v ninja >/dev/null 2>&1; then
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get install -y ninja-build
else
brew install ninja
fi
fi

- name: Configure
run: |
AGENT_ARCH="$(uname -m)"
# NANO_POSIX_ARCH is only used on macOS to set CMAKE_OSX_ARCHITECTURES.
# On Linux the host toolchain architecture is used automatically.
if [ "${AGENT_ARCH}" = "arm64" ]; then
ARCH_FLAG="-DNANO_POSIX_ARCH=arm64"
else
ARCH_FLAG="-DNANO_POSIX_ARCH=x86_64"
fi
cmake -S targets/posix -B build/posix -G Ninja \
${ARCH_FLAG} \
-DNANO_POSIX_ENABLE_SMOKE=ON

- name: Build
run: cmake --build build/posix --verbose

- name: Smoke Run
run: |
set -euo pipefail
./build/posix/bin/nanoFramework.nanoCLR.test | tee build/posix/smoke.log
if ! grep -Eq '[0-9]+\.[0-9]+\.[0-9]+' build/posix/smoke.log; then
echo "ERROR: smoke output validation failed."
exit 1
fi
Comment thread
Ellerbach marked this conversation as resolved.

- name: Upload Artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: posix-nanoclr-${{ matrix.label }}
path: |
build/posix/lib/nanoFramework.nanoCLR.*
build/posix/bin/nanoFramework.nanoCLR.test
build/posix/smoke.log
142 changes: 141 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ jobs:
echo "##vso[task.setvariable variable=BUILD_TI;isOutput=true]false"
echo "##vso[task.setvariable variable=BUILD_THREADX;isOutput=true]false"
echo "##vso[task.setvariable variable=BUILD_WIN32;isOutput=true]false"
echo "##vso[task.setvariable variable=BUILD_POSIX;isOutput=true]false"
echo "##vso[task.setvariable variable=BUILD_NANOCLR_CLI;isOutput=true]false"
echo "##vso[task.setvariable variable=BUILD_ALL;isOutput=true]false"

Expand Down Expand Up @@ -252,6 +253,14 @@ jobs:

Write-host "##[command] Building nanoCLR target"
}

if( ($files.where{$_.Contains('targets/posix')}).Count -gt 0)
{
# files at POSIX folder
echo "##vso[task.setvariable variable=BUILD_POSIX;isOutput=true]true"

Write-host "##[command] Building POSIX nanoCLR target"
}

if(
(($files.where{$_.Contains('targets/netcore/nanoFramework.nanoCLR.CLI')}).Count -gt 0) -Or
Expand Down Expand Up @@ -347,7 +356,8 @@ jobs:
eq(dependencies.Check_Build_Options.outputs['TargetsToBuild.BUILD_FREERTOS'], true),
eq(dependencies.Check_Build_Options.outputs['TargetsToBuild.BUILD_TI'], true),
eq(dependencies.Check_Build_Options.outputs['TargetsToBuild.BUILD_THREADX'], true),
eq(dependencies.Check_Build_Options.outputs['TargetsToBuild.BUILD_WIN32'], true)
eq(dependencies.Check_Build_Options.outputs['TargetsToBuild.BUILD_WIN32'], true),
eq(dependencies.Check_Build_Options.outputs['TargetsToBuild.BUILD_POSIX'], true)
)
)

Expand Down Expand Up @@ -1026,6 +1036,134 @@ jobs:

- template: azure-pipelines-templates/publish-nanoclr.yml

#################
# POSIX host target (macOS + Linux)
- job: Build_POSIX_nanoCLR
strategy:
matrix:
macOS:
vmImage: 'macos-14'
Linux:
vmImage: 'ubuntu-22.04'
maxParallel: 2
condition: >-
or(
and(
succeeded('Check_Code_Style'),
ne( dependencies.Check_Build_Options.outputs['BuildOptions.SKIP_BUILD'], true ),
or(
eq(dependencies.Check_Build_Options.outputs['TargetsToBuild.BUILD_ALL'], true),
eq(dependencies.Check_Build_Options.outputs['TargetsToBuild.BUILD_POSIX'], true)
)
),
and(
eq(variables['Build.Reason'], 'Manual'),
or(
eq(variables['BUILD_ALL__'], 'true'),
eq(variables['BUILD_POSIX__'], 'true')
)
)
)

dependsOn:
- Check_Build_Options
- Check_Code_Style

pool:
vmImage: $(vmImage)

variables:
- group: sign-client-credentials

steps:
- checkout: self

- bash: |
set -euo pipefail
if [[ "${BUILD_SOURCEBRANCH}" == *"develop"* || "${BUILD_SOURCEBRANCH}" == *"release"* || "${FORCEUPLOAD}" == "true" ]]; then
echo "##vso[task.setvariable variable=CLOUDSMITH_REPO]nanoframework-images-dev"
else
echo "##vso[task.setvariable variable=CLOUDSMITH_REPO]nanoframework-images"
fi
displayName: Set Cloudsmith repo path
env:
BUILD_SOURCEBRANCH: $(Build.SourceBranch)
FORCEUPLOAD: $(ForceUpload)

- bash: |
set -euo pipefail

AGENT_ARCH="$(uname -m)"
if [ "${AGENT_ARCH}" = "arm64" ]; then
ARCH_FLAG="-DNANO_POSIX_ARCH=arm64"
else
ARCH_FLAG="-DNANO_POSIX_ARCH=x86_64"
fi

# Install ninja if not present (Linux agents)
if ! command -v ninja >/dev/null 2>&1; then
sudo apt-get install -y ninja-build
fi

echo "Agent architecture: ${AGENT_ARCH}"

cmake -S targets/posix -B build/posix -G Ninja ${ARCH_FLAG} -DNANO_POSIX_ENABLE_SMOKE=ON
cmake --build build/posix
./build/posix/bin/nanoFramework.nanoCLR.test | tee build/posix/smoke.log
if ! grep -Eq '[0-9]+\.[0-9]+\.[0-9]+' build/posix/smoke.log; then
echo "ERROR: smoke output validation failed, expected semantic version in output."
exit 1
fi

# Extract CLR version (e.g. "1.16.0.0") from the smoke output for use in artifact naming.
CLR_VERSION=$(grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' build/posix/smoke.log | head -1)
echo "Detected CLR version: ${CLR_VERSION}"
echo "##vso[task.setvariable variable=POSIX_CLR_VERSION]${CLR_VERSION}"

# Stage the native shared library for artifact publish and Cloudsmith upload.
if [[ "$(uname)" == "Darwin" ]]; then
LIB_EXT="dylib"
PKG_NAME="MACOS_DYLIB_nanoCLR"
else
LIB_EXT="so"
PKG_NAME="LINUX_SO_nanoCLR"
fi
mkdir -p "$(Build.ArtifactStagingDirectory)/${PKG_NAME}"
cp "build/posix/lib/nanoFramework.nanoCLR.${LIB_EXT}" \
"$(Build.ArtifactStagingDirectory)/${PKG_NAME}/"
echo "##vso[task.setvariable variable=POSIX_PKG_NAME]${PKG_NAME}"
echo "##vso[task.setvariable variable=POSIX_LIB_EXT]${LIB_EXT}"
displayName: Build and smoke run POSIX nanoCLR

- task: PublishPipelineArtifact@1
condition: succeeded()
displayName: Publish POSIX nanoCLR artifact
inputs:
targetPath: "$(Build.ArtifactStagingDirectory)"
artifactName: nanoclr_posix_$(Agent.OS)
artifactType: pipeline

- bash: |
set -euo pipefail
pip install --upgrade cloudsmith-cli --quiet
cloudsmith push raw net-nanoframework/$(CLOUDSMITH_REPO) \
"$(Build.ArtifactStagingDirectory)/$(POSIX_PKG_NAME)/nanoFramework.nanoCLR.$(POSIX_LIB_EXT)" \
--name "$(POSIX_PKG_NAME)" \
--version "$(POSIX_CLR_VERSION)" \
-k "$(CLOUDSMITH_KEY)"
condition: >-
and(
succeeded(),
or(
eq(variables['ForceUpload'], true),
and(
eq(variables['Build.SourceBranchName'], 'main'),
eq(variables['System.PullRequest.PullRequestId'], '')
)
)
)
displayName: Upload POSIX nanoCLR to Cloudsmith

#################
# nanoCLR CLI tool
- job: Build_nanoCLR_CLI
Expand Down Expand Up @@ -1340,6 +1478,7 @@ jobs:
- Build_TI_SimpleLink_targets
- Build_ThreadX_targets
- Build_WIN32_nanoCLR
- Build_POSIX_nanoCLR
- Build_nanoCLR_CLI
- Check_Code_Style
condition: >-
Expand All @@ -1352,6 +1491,7 @@ jobs:
failed('Build_TI_SimpleLink_targets'),
failed('Build_ThreadX_targets'),
failed('Build_WIN32_nanoCLR'),
failed('Build_POSIX_nanoCLR'),
failed('Build_nanoCLR_CLI')
)
)
Expand Down
24 changes: 24 additions & 0 deletions src/CLR/Core/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,30 @@ HRESULT CLR_RT_Thread::ProcessException_Phase2()
// m_currentException is still set, but we return PROCESS_EXCEPTION signalling that there is no hope for the thread,
// which causes Thread::Execute to terminate it.

#if !defined(BUILD_RTM)
// Print the unhandled exception type regardless of debugger availability.
if ((this->m_flags & CLR_RT_Thread::TH_F_Aborted) == 0)
{
CLR_RT_HeapBlock *pException = m_currentException.Dereference();
if (pException != NULL)
{
CLR_RT_TypeDef_Instance cls{};
if (cls.InitializeFromIndex(pException->ObjectCls()))
{
CLR_Debug::Printf(
"#### Exception %s::%s - 0x%08x ####\r\n",
cls.m_assm->GetString(cls.m_target->nameSpace),
cls.m_assm->GetString(cls.m_target->name),
(int)hr);
}
else
{
CLR_Debug::Printf("#### (unknown) Exception - 0x%08x ####\r\n", (int)hr);
}
}
}
#endif

#if defined(NANOCLR_ENABLE_SOURCELEVELDEBUGGING)
if (CLR_EE_DBG_IS_NOT(NoStackTraceInExceptions))
{
Expand Down
6 changes: 6 additions & 0 deletions src/CLR/Helpers/nanoprintf/nanoprintf.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
#define NANOPRINTF_H

#include <stdarg.h>
// size_t is guaranteed by C11/C++11, but some bare-metal toolchains pull it
// in transitively. On POSIX hosts (and for any standalone compile) include
// <stddef.h> explicitly so that PRINTF_T / size_t can be resolved.
#if defined(PLATFORM_POSIX_HOST) || !defined(__arm__)
#include <stddef.h>
#endif

// clang-format off

Expand Down
2 changes: 1 addition & 1 deletion src/CLR/Include/nanoCLR_Hardware.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ extern CLR_HW_Hardware g_CLR_HW_Hardware;
// keep under control the size of the HalInterruptRecord, since we will use externally
// defined arrays to handle those data structures in the interrupt dispatching

#ifdef _WIN64
#if defined(_WIN64) || (defined(PLATFORM_POSIX_HOST) && defined(__LP64__))
CT_ASSERT(sizeof(CLR_HW_Hardware::HalInterruptRecord) == 32)
#else
CT_ASSERT(sizeof(CLR_HW_Hardware::HalInterruptRecord) == 24)
Expand Down
6 changes: 3 additions & 3 deletions src/CLR/Include/nanoCLR_PlatformDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// ARM & ESP32
#if defined(PLATFORM_ARM) || defined(PLATFORM_ESP32)
// ARM, ESP32 & POSIX host
#if defined(PLATFORM_ARM) || defined(PLATFORM_ESP32) || defined(PLATFORM_POSIX_HOST)
// #define NANOCLR_STRESS_GC
// #define NANOCLR_GC_VERBOSE
// #define NANOCLR_PROFILE_NEW
Expand Down Expand Up @@ -175,7 +175,7 @@
#define ULONGLONGCONSTANT(v) (v##UI64)
#endif

#if defined(PLATFORM_ARM) | defined(PLATFORM_ESP32)
#if defined(PLATFORM_ARM) || defined(PLATFORM_ESP32) || defined(PLATFORM_POSIX_HOST)
#define PROHIBIT_ALL_CONSTRUCTORS(cls) \
private: \
cls(); \
Expand Down
23 changes: 13 additions & 10 deletions src/CLR/Include/nanoCLR_Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -2475,17 +2475,12 @@ CT_ASSERT(
#endif

CT_ASSERT(
offsetof(CLR_RT_StackFrame, CLR_RT_StackFrame::m_owningThread) + sizeof(CLR_RT_Thread *) ==
offsetof(CLR_RT_StackFrame, CLR_RT_StackFrame::m_evalStack))
CT_ASSERT(
offsetof(CLR_RT_StackFrame, CLR_RT_StackFrame::m_evalStack) + sizeof(CLR_RT_HeapBlock *) ==
offsetof(CLR_RT_StackFrame, CLR_RT_StackFrame::m_arguments))
offsetof(CLR_RT_StackFrame, m_owningThread) + sizeof(CLR_RT_Thread *) == offsetof(CLR_RT_StackFrame, m_evalStack))
CT_ASSERT(
offsetof(CLR_RT_StackFrame, CLR_RT_StackFrame::m_arguments) + sizeof(CLR_RT_HeapBlock *) ==
offsetof(CLR_RT_StackFrame, CLR_RT_StackFrame::m_locals))
offsetof(CLR_RT_StackFrame, m_evalStack) + sizeof(CLR_RT_HeapBlock *) == offsetof(CLR_RT_StackFrame, m_arguments))
CT_ASSERT(
offsetof(CLR_RT_StackFrame, CLR_RT_StackFrame::m_locals) + sizeof(CLR_RT_HeapBlock *) ==
offsetof(CLR_RT_StackFrame, CLR_RT_StackFrame::m_IP))
offsetof(CLR_RT_StackFrame, m_arguments) + sizeof(CLR_RT_HeapBlock *) == offsetof(CLR_RT_StackFrame, m_locals))
CT_ASSERT(offsetof(CLR_RT_StackFrame, m_locals) + sizeof(CLR_RT_HeapBlock *) == offsetof(CLR_RT_StackFrame, m_IP))

#ifdef __GNUC__
#pragma GCC diagnostic pop
Expand Down Expand Up @@ -3908,19 +3903,23 @@ extern CLR_UINT32 g_buildCRC;

#ifdef _WIN64
CT_ASSERT(sizeof(struct CLR_RT_HeapBlock) == 20)
#elif defined(PLATFORM_POSIX_HOST) && defined(__LP64__)
// 64-bit POSIX host: HeapBlock layout will be determined during port; skip size check
#else
Comment thread
Ellerbach marked this conversation as resolved.
CT_ASSERT(sizeof(struct CLR_RT_HeapBlock) == 12)
#endif // _WIN64

#if !defined(PLATFORM_POSIX_HOST) || !defined(__LP64__)
CT_ASSERT(sizeof(CLR_RT_HeapBlock_Raw) == sizeof(struct CLR_RT_HeapBlock))
#endif

#if defined(NANOCLR_TRACE_MEMORY_STATS)
#define NANOCLR_TRACE_MEMORY_STATS_EXTRA_SIZE sizeof(const char *)
#else
#define NANOCLR_TRACE_MEMORY_STATS_EXTRA_SIZE 0
#endif

#if defined(__GNUC__) // Gcc compiler uses 8 bytes for a function pointer
#if defined(__GNUC__) && !defined(PLATFORM_POSIX_HOST) // Gcc compiler uses 8 bytes for a function pointer
CT_ASSERT(sizeof(CLR_RT_DataTypeLookup) == 20 + NANOCLR_TRACE_MEMORY_STATS_EXTRA_SIZE)

#elif defined(VIRTUAL_DEVICE) && defined(NANOCLR_TRACE_MEMORY_STATS)
Expand All @@ -3941,7 +3940,11 @@ CT_ASSERT(sizeof(CLR_RT_DataTypeLookup) == 16 + NANOCLR_TRACE_MEMORY_STATS_EXTRA

#else

#if defined(PLATFORM_POSIX_HOST) && defined(__LP64__)
// 64-bit POSIX host: structure sizes will differ from embedded ARM; skip checks during port.
#else
!ERROR
#endif

#endif

Expand Down
Loading
Loading