Skip to content

[wip] esp32c3 println path + linker map output#1619

Draft
luoliwoshang wants to merge 1 commit intoxgo-dev:mainfrom
luoliwoshang:codex/wip-esp32c3-println-map
Draft

[wip] esp32c3 println path + linker map output#1619
luoliwoshang wants to merge 1 commit intoxgo-dev:mainfrom
luoliwoshang:codex/wip-esp32c3-println-map

Conversation

@luoliwoshang
Copy link
Copy Markdown
Contributor

Summary

  • add -map build flag to emit linker map files (supports explicit path and auto)
  • wire linker map handling through build config and linker argument selection
  • add unit tests for map flag resolution and driver/linker argument selection
  • route runtime.PrintString/PrintByte through platform-specific helpers
  • on baremetal && esp, send println output via C.write (fd=2) to avoid stdio path issues

Validation

  • go test ./internal/build -run "Test(UseCompilerDriverMapFlags|ResolveLinkMapArgs)$"
  • llgo build -a -target=esp32c3 _demo/embed/esp32c3/println
  • hardware run confirms println("Hello") now prints Hello, then exits via _exit panic path (current runtime behavior)

@gemini-code-assist
Copy link
Copy Markdown
Contributor

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 enhances the build system by adding support for generating linker map files, which are crucial for debugging and optimizing binary sizes in embedded systems. Concurrently, it addresses a critical issue with println output on ESP32-C3 targets by implementing a direct, platform-specific write mechanism, ensuring reliable console output for embedded applications.

Highlights

  • Linker Map File Generation: Introduced a new -map build flag to allow users to generate linker map files. This flag supports specifying an explicit output path or using 'auto' to derive the map file name from the output executable.
  • Platform-Specific Println Implementation: Refactored runtime.PrintString and runtime.PrintByte to use platform-specific helper functions. For baremetal && esp targets (like ESP32-C3), output is now routed directly through C.write to stderr (file descriptor 2) to bypass standard I/O path issues.
  • Build Configuration and Argument Handling: Integrated the linker map file handling into the build configuration and added logic to select appropriate linker arguments based on whether a compiler driver (like Clang/GCC) or a direct linker (like ld.lld) is being used.
  • Unit Tests for Linker Map Logic: Added comprehensive unit tests to validate the resolution of the -map flag and the correct selection of linker arguments for various toolchain configurations.

🧠 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.

Changelog
  • cmd/internal/flags/flags.go
    • Added LinkMapFile global variable to store the value of the new -map flag.
    • Introduced the -map command-line flag for specifying linker map file output.
    • Updated UpdateConfig to propagate the LinkMapFile value to the build configuration.
  • internal/build/build.go
    • Added LinkMapFile field to the Config struct to store the linker map output path.
    • Modified linkObjFiles to incorporate linker map arguments if the LinkMapFile is specified in the build configuration.
    • Implemented resolveLinkMapArgs function to determine the map file path and the correct linker arguments based on the output path and LinkMapFile setting.
    • Added useCompilerDriverMapFlags function to detect if the linker is a compiler driver (e.g., Clang, GCC) that requires -Xlinker prefix for map flags.
  • internal/build/link_map_test.go
    • New file containing unit tests for useCompilerDriverMapFlags to verify correct detection of compiler drivers.
    • New file containing unit tests for resolveLinkMapArgs to ensure proper map file path resolution and argument generation for various scenarios.
  • runtime/internal/clite/c.go
    • Added //go:linkname Write C.write binding to expose the write system call from C standard library.
  • runtime/internal/runtime/z_print.go
    • Modified PrintByte to call a new printByte helper function.
    • Modified PrintString to call a new printString helper function.
  • runtime/internal/runtime/z_print_impl_baremetal_esp.go
    • New file implementing printByte and printString specifically for baremetal && esp targets.
    • These implementations use C.Write to stderrFD (file descriptor 2) for direct output.
  • runtime/internal/runtime/z_print_impl_default.go
    • New file implementing default printByte and printString functions for non-baremetal && esp targets.
    • These default implementations continue to use c.Fputc and c.Fwrite to c.Stderr.
Activity
  • The pull request is marked as [wip], indicating ongoing development.
  • The author has provided a detailed summary of changes and validation steps.
  • Validation includes running specific go test commands for linker map flag resolution and llgo build for the ESP32-C3 println demo.
  • Hardware validation on an ESP32-C3 confirmed that println("Hello") now correctly prints and exits.
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
Copy Markdown
Contributor

@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 introduces two main enhancements: the ability to generate a linker map file via a -map flag, and a platform-specific implementation for println on esp32c3 baremetal targets. The changes are well-structured and include relevant unit tests for the new linker flag functionality. The println refactoring correctly uses build tags to separate platform-specific code.

I have one suggestion to improve the efficiency of the new printByte implementation for the esp target by avoiding repeated stack allocations. Overall, this is a solid contribution.

Comment on lines +25 to +28
func printByte(v byte) {
ch := v
c.Write(stderrFD, c.Pointer(&ch), 1)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The current implementation of printByte allocates a new variable ch on the stack for every byte printed. While this is safe, it can be inefficient if printByte is called within a tight loop. To improve performance, you could use a package-level buffer to avoid repeated stack allocations. Since this is for a baremetal target, concurrency is not a concern for a package-level variable.

var printByteBuf [1]byte

func printByte(v byte) {
	printByteBuf[0] = v
	c.Write(stderrFD, c.Pointer(&printByteBuf[0]), 1)
}

@@ -0,0 +1,110 @@
package build
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor: Consider adding a license header to this test file for consistency with other test files in the directory (e.g., cache_test.go, fingerprint_test.go).

{name: "derive from cc", linker: "", cc: "clang++", want: true},
{name: "derive ld from cc", linker: "", cc: "ld.lld", want: false},
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The test coverage for useCompilerDriverMapFlags could be improved. Consider adding test cases for:

  1. g++ variants (tests strings.HasSuffix(base, "g++") branch):
{name: "g++ linker", linker: "g++", cc: "", want: true},
{name: "cross g++ linker", linker: "arm-none-eabi-g++", cc: "", want: true},
  1. Additional CC fallback scenarios:
{name: "derive gcc from cc", linker: "", cc: "gcc", want: true},
{name: "derive g++ from cc", linker: "", cc: "g++", want: true},

@fennoai
Copy link
Copy Markdown
Contributor

fennoai Bot commented Feb 6, 2026

Code Review Summary

Overall: Clean implementation that follows existing codebase patterns well. The -map flag logic and platform-specific print abstraction are well-structured.

Strengths:

  • Early return for disabled map feature ensures zero cost when not used
  • Build tags are correct and complementary for platform-specific files
  • Table-driven tests follow established patterns

Minor suggestions: See inline comments for missing test cases for g++ compiler variants and license header consistency.

No security or performance concerns identified.

@luoliwoshang luoliwoshang marked this pull request as draft February 6, 2026 07:59
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.04%. Comparing base (ba290e2) to head (35b97e4).
⚠️ Report is 32 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1619      +/-   ##
==========================================
- Coverage   91.06%   91.04%   -0.02%     
==========================================
  Files          45       45              
  Lines       11938    11917      -21     
==========================================
- Hits        10871    10850      -21     
  Misses        892      892              
  Partials      175      175              

☔ 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