Skip to content

builder,interp: fix -ldflags -X not overriding variables with default values#5344

Closed
abgoyal wants to merge 1 commit intotinygo-org:devfrom
abgoyal:fix-ldflags-x-override
Closed

builder,interp: fix -ldflags -X not overriding variables with default values#5344
abgoyal wants to merge 1 commit intotinygo-org:devfrom
abgoyal:fix-ldflags-x-override

Conversation

@abgoyal
Copy link
Copy Markdown
Contributor

@abgoyal abgoyal commented Apr 23, 2026

Currently, -ldflags "-X pkg.Var=value" fails to override string variables that have a default value in source code:

var Version = "dev"  // -X override is ignored, stays "dev"
var Version string   // -X override works correctly

In standard Go, -X works in both cases. This patch brings TinyGo's behavior in line with Go.

The root cause is the timing of when -X values are applied relative to the interp pass. The previous approach:

  1. Erase global, make it undefined
  2. Run interp (executes Version = "dev" from init code)
  3. Link in -X value via makeGlobalsModule

By step 2, interp had already stored the default value, and the linking step couldn't reliably override it.

This patch changes the approach:

  1. Set -X value as initializer before interp runs
  2. Run interp, but skip stores to -X globals
  3. Global retains the -X value

This also means dependent compile-time computations work correctly:

var Version = "dev"
var VersionLen = len(Version)  // now evaluates with -X value

With this fix, makeGlobalsModule becomes redundant - we no longer need a separate module to work around type renaming issues since we set the value directly on the global using its existing type during per-package compilation.

I've removed makeGlobalsModule as part of this change. If there are edge cases I haven't considered where keeping it would be safer, happy to restore it as a fallback.

… values

Currently, -ldflags "-X pkg.Var=value" fails to override string variables
that have a default value in source code:

    var Version = "dev"  // -X override is ignored, stays "dev"
    var Version string   // -X override works correctly

In standard Go, -X works in both cases. This patch brings TinyGo's
behavior in line with Go.

The root cause is the timing of when -X values are applied relative to
the interp pass. The previous approach:

  1. Erase global, make it undefined
  2. Run interp (executes `Version = "dev"` from init code)
  3. Link in -X value via makeGlobalsModule

By step 2, interp had already stored the default value, and the linking
step couldn't reliably override it.

This patch changes the approach:

  1. Set -X value as initializer before interp runs
  2. Run interp, but skip stores to -X globals
  3. Global retains the -X value

This also means dependent compile-time computations work correctly:

    var Version = "dev"
    var VersionLen = len(Version)  // now evaluates with -X value

With this fix, makeGlobalsModule becomes redundant - we no longer need
a separate module to work around type renaming issues since we set the
value directly on the global using its existing type during per-package
compilation.

I've removed makeGlobalsModule as part of this change. If there are edge
cases I haven't considered where keeping it would be safer, happy to
restore it as a fallback.
@abgoyal abgoyal closed this Apr 23, 2026
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