Skip to content

Conversation

@luoliwoshang
Copy link
Member

@luoliwoshang luoliwoshang commented Jan 15, 2026

变更说明

  • 增加 ESP32-C3 模拟器测试:复用 cltest.RunFromDir./_testgo
  • 引入可配置的运行选项与输出过滤(过滤 entry 0x... 之前的启动日志)
  • 通过 allow/ignore 列表显式声明当前可运行用例(先放行 ./_testgo/print

设计要点

  • TestRunESP32C3Emulator 风格与 TestRunFromTestgo 保持一致,方便后续扩展到其他嵌入式目标
  • 输出过滤逻辑集中在 cltest.FilterEmulatorOutput,便于复用与维护

测试

  • 未在本地运行(需要 ESP32-C3 QEMU 环境)

luoliwoshang and others added 28 commits January 15, 2026 16:06
ESP32-C3 bootloader starts at flash offset 0x0, unlike ESP32 which
starts at 0x1000. The previous code added 4KB padding for all ESP
chips, causing QEMU to fail with "invalid header: 0x00000000" when
trying to boot ESP32-C3 images.

This fix only adds the 4KB padding for ESP32 (Xtensa), while ESP32-C3
(RISC-V) images now start at offset 0x0 as expected by its ROM
bootloader.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Add emulator command configuration to esp32c3.json target file,
enabling ESP32-C3 programs to run in QEMU emulator with:
  llgo run -target=esp32c3 -emulator .

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Add missing newlines at end of esp32c3.json and esp32c3-basic.json
to follow standard file formatting conventions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
    Remove conflicting _exit implementations from libnosys and libgloss to
    ensure the semihosting version (from semihost-sys_exit.c, added as .o
    in goplus#1537) is used for ESP32-C3 QEMU emulator.

    Changes:
    - Comment out libnosys/_exit.c
    - Comment out libgloss/riscv/sys_exit.c (3 occurrences)

    This allows proper exit handling in QEMU emulator via semihosting
    protocol instead of using the  instruction which causes crashes.

    Related: goplus#1537

    🤖 Generated with [Claude Code](https://claude.com/claude-code)

    Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add -semihosting flag to QEMU command to enable proper program exit
using semihosting _exit implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Update newlib version to patch5 which includes the split of _exit
from syscalls.c to syscalls_exit.c.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Remove libgloss/libnosys/_exit.c from RISC-V compile list to ensure
semihosting _exit is used for QEMU emulator support.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Update test script to use project directory for temp files
  (enables go.mod module resolution)
- Use real Hello World program in test instead of empty program
  (ensures .rodata has PROGBITS type for proper BIN generation)
- Remove duplicate semihost-sys_exit.c from RISC-V config
  (was causing conflict with custom _exit implementation)
- Fix whitespace in linker script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Move semihost-sys_exit.c to its own library (libsemihost-{target}.a)
for cleaner separation of semihosting support from core startup code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
These semihost syscall files are not actually used - only semihost-sys_exit.c
is needed for QEMU emulator support (now in separate libsemihost library).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Update libc_test.go to reflect the new 4-group structure for RISC-V:
- Group 0: libsemihost (semihosting _exit for QEMU)
- Group 1: libcrt0 (board startup)
- Group 2: libgloss (system stubs)
- Group 3: libc (C library)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add comprehensive test framework for running embedded programs in QEMU emulator:

Architecture:
- Tests located in cl/_testemb/ (parallel to existing cl tests)
- Uses build.Do() directly (similar to build_test.go pattern)
- Auto-discovers test cases: any directory with main.go + expect.txt

Features:
- TestEmbRun runs all tests across multiple targets (ESP32C3, ESP32)
- filterEmulatorOutput() extracts program output after "entry 0x..." line
- Logs both filtered and full emulator output for debugging
- Test case structure:
  cl/_testemb/
  └── cprintf/
      ├── main.go     # Test program
      └── expect.txt  # Expected output

Usage:
  export PATH="/path/to/esp-qemu/bin:$PATH"
  go test ./cl -run TestEmbRun -v

Adding new tests: just create new directory with main.go + expect.txt

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add workflow step to install ESP32 RISC-V QEMU emulator for running embedded tests.

Script features (.github/workflows/install-esp-qemu.sh):
- Accepts installation directory as argument (default: .cache/qemu)
- Auto-detects platform (OS + architecture)
- Downloads platform-specific QEMU from espressif/qemu releases (v9.2.2)
- Supports: macOS (x86_64/aarch64) and Linux (x86_64/aarch64)
- Downloads and extracts to specified directory
- Verifies qemu-system-riscv32 binary exists after installation

CI integration (go.yml):
- Installs QEMU to .cache/qemu before running tests
- Adds QEMU bin directory to PATH for subsequent steps
- Verifies installation with version check
- Required for cl/embed_test.go emulator tests

Verified file structure:
.cache/qemu/
└── bin/
    └── qemu-system-riscv32

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
ESP32 QEMU requires libSDL2-2.0.so.0 shared library on Linux.

Error without SDL2:
  qemu-system-riscv32: error while loading shared libraries:
  libSDL2-2.0.so.0: cannot open shared object file: No such file or directory

Solution:
- Add libsdl2-2.0-0 to Ubuntu common dependencies
- macOS already has SDL2 bundled with QEMU or available via brew

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
1. Add SDL2 dependency for macOS
   - ESP32 QEMU requires libSDL2-2.0.0.dylib on macOS
   - Error: Library not loaded: /opt/homebrew/opt/sdl2/lib/libSDL2-2.0.0.dylib
   - Solution: brew install sdl2

2. Remove ESP32 (Xtensa) test from embed_test.go
   - Only keep ESP32C3 (RISC-V) test
   - ESP32 Xtensa QEMU requires separate setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace t.Logf() with fmt.Printf() to always show test output regardless of -v flag.

Benefits:
- CI logs always show program output even without go test -v
- Easier debugging when tests fail
- Consistent visibility in all environments

Output format:
=== Test Output for <test_name> ===
Program output:
<filtered output>
Full emulator output:
<complete emulator log>
========================

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Restore temporarily deleted workflow files:
- build-cache.yml
- doc-link-checker.yml
- doc.yml
- fmt.yml
- llgo.yml
- release-build.yml
- stdlib-coverage.yml
- targets.yml

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add //go:build !llgo and // +build !llgo tags to embed_test.go
to prevent it from being compiled by llgo itself.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Drop cl/_testemb harness and embed_test.go since the emulator test flow is being replaced.

Extend _demo/embed/test_esp32c3_startup.sh to run QEMU and assert the final output line, printing full logs on mismatch.

Co-authored-by: Codex <[email protected]>
Introduce setup-embed-deps to install SDL2 runtime requirements for QEMU.

Use it in go.yml and llgo.yml before embedded tests.
Move ESP32 RISC-V QEMU install/verify steps into setup-embed-deps.

Use setup-embed-deps only in llgo.yml's llgo job and remove duplicate steps from go.yml.
Embed QEMU dependencies now live in setup-embed-deps.
Add a filtered ESP32-C3 emulator smoke test that runs a minimal program and validates output.

Reuse a shared filter for entry-line boot logs with explicit fixtures.
@gemini-code-assist
Copy link

Summary of Changes

Hello @luoliwoshang, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the testing framework for embedded systems, particularly for the ESP32-C3 microcontroller. It introduces dedicated emulator tests, refines the build and test execution process with flexible configuration options and output filtering, and updates core library configurations. These changes aim to enhance the reliability and maintainability of embedded software development by providing a more robust and automated testing environment.

Highlights

  • ESP32-C3 Emulator Coverage: Added a new 'hello world' test specifically for the ESP32-C3 target, designed to run within an emulator environment to ensure basic functionality and output.
  • Enhanced Test Runner: The cltest.RunFromDir function has been extended with new options, WithRunConfig and WithOutputFilter, allowing for custom build configurations and the ability to filter emulator boot logs before comparing test output.
  • New ESP32-C3 Target Definition: A new esp32c3-basic.json target has been introduced, defining the specific configurations and emulator command for the ESP32-C3 RISC-V architecture.
  • Newlib Update and Refactoring: The Newlib ESP32 configuration has been updated to 'patch5', and the RISC-V compile groups have been refactored to include a separate libsemihost group, improving the organization and handling of semihosting functionalities.
  • Firmware Image Creation Adjustment: The firmware image creation logic for ESP devices has been updated to conditionally add 4KB padding only for ESP32 (Xtensa) chips, removing it for ESP32-C3 (RISC-V) as its bootloader starts at 0x0.
  • GitHub Actions for Embedded Dependencies: A new GitHub Action (setup-embed-deps) has been added to automate the installation of necessary embedded dependencies, including SDL2 and ESP32 RISC-V QEMU, for CI/CD environments.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: .github/workflows/** (3)
    • .github/workflows/go.yml
    • .github/workflows/install-esp-qemu.sh
    • .github/workflows/llgo.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds emulator test coverage for the ESP32-C3 target. The changes include adding a new esp32c3-basic target for emulation, extending the cltest helpers with support for custom run configurations and output filtering, and adding a new test case that runs on the QEMU emulator. The refactoring of the ESP32-C3 target configuration and the newlib build process to separate semihosting logic are good improvements for maintainability. My feedback includes a minor performance improvement for the new test helper.

// FilterEmulatorOutput strips emulator boot logs by returning output after "entry 0x...".
func FilterEmulatorOutput(output string) string {
lines := strings.Split(output, "\n")
entryPattern := regexp.MustCompile(`^entry 0x[0-9a-fA-F]+$`)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Compiling a regular expression on every function call is inefficient, especially since this function might be called in a loop during tests. It's better to compile it once at the package level and reuse the compiled object.

Please remove this line and define entryPattern as a package-level variable:

var entryPattern = regexp.MustCompile(`^entry 0x[0-9a-fA-F]+$`)


// FilterEmulatorOutput strips emulator boot logs by returning output after "entry 0x...".
func FilterEmulatorOutput(output string) string {
lines := strings.Split(output, "\n")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex is compiled on every function call. Since this filter is invoked for each test case, consider moving the pattern to a package-level variable:

Suggested change
lines := strings.Split(output, "\n")
var entryPattern = regexp.MustCompile(`^entry 0x[0-9a-fA-F]+$`)
// FilterEmulatorOutput strips emulator boot logs by returning output after "entry 0x...".
func FilterEmulatorOutput(output string) string {
lines := strings.Split(output, "\n")

;;
esac

# Download URL
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The version string uses underscores but the release tag uses hyphens. A brief comment would help prevent future maintainers from accidentally "fixing" this discrepancy:

Suggested change
# Download URL
# Note: VERSION uses underscores per Espressif's filename convention,
# while the release tag uses hyphens.
VERSION="esp_develop_9.2.2_20250817"

@xgopilot
Copy link

xgopilot bot commented Jan 15, 2026

Code Review Summary

This PR adds comprehensive ESP32-C3 emulator test coverage with well-structured CI infrastructure. The functional options pattern in RunFromDir is idiomatic Go, and the JSON inheritance for target configs is clean.

One improvement to address:

  • Move entryPattern regex to package level in FilterEmulatorOutput to avoid recompiling on each call.

Optional enhancement:

  • Consider adding checksum verification in install-esp-qemu.sh for enhanced supply chain security (not blocking).

Overall, solid implementation with good test coverage for embedded targets.

@luoliwoshang luoliwoshang force-pushed the feat/esp32c3-emulator-testgo branch from c3fa8db to 7f7063b Compare January 15, 2026 08:30
@luoliwoshang luoliwoshang changed the title test(esp32c3): add emulator run coverage test(esp32c3): run _testgo on emulator Jan 15, 2026
Extend cltest.RunFromDir with optional run config/output filter for emulator runs.

Add ESP32/ESP32-C3 boot log filter fixtures and run a filtered allowlist from ./_testgo.
@luoliwoshang luoliwoshang force-pushed the feat/esp32c3-emulator-testgo branch from 7f7063b to 46663b7 Compare January 15, 2026 08:35
@codecov
Copy link

codecov bot commented Jan 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.01%. Comparing base (f6337d4) to head (4d84e8d).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1567      +/-   ##
==========================================
- Coverage   91.01%   91.01%   -0.01%     
==========================================
  Files          45       45              
  Lines       11971    11966       -5     
==========================================
- Hits        10896    10891       -5     
  Misses        899      899              
  Partials      176      176              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant