Skip to content

build: isolate invocation configuration and execution - #2212

Merged
xushiwei merged 1 commit into
xgo-dev:mainfrom
zhouguangyuan0718:agent/build-isolation-01-context
Jul 31, 2026
Merged

build: isolate invocation configuration and execution#2212
xushiwei merged 1 commit into
xgo-dev:mainfrom
zhouguangyuan0718:agent/build-isolation-01-context

Conversation

@zhouguangyuan0718

@zhouguangyuan0718 zhouguangyuan0718 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • initialize each LLGo command process PATH once, before builds start, from the existing llvm.New("").BinDir() discovery
  • keep LLVM executables as process background instead of storing an LLVM installation in Config, build context, or backend workers
  • introduce Invocation as the explicit Build input and keep Do(args, conf) as its compatibility wrapper
  • clone caller-owned Config before resolving defaults and compatibility settings
  • snapshot the invocation working directory and process environment once, then pass them explicitly to package loading and subprocesses
  • restrict the internal commandEnv value to only child-process Dir and Env; cgo, pkg-config, llc, run, and emulator leaf helpers no longer receive the full compiler context only for those values
  • move output-directory creation from configuration time to the actual link operation

LLVM process model

LLVM_CONFIG is a process-startup choice. The shipped cmd/llgo entry point and repository tools that invoke build.Do call llvm.SetupPath() before starting builds. It prepends the selected bin directory using the platform path-list separator, ignores an empty directory, and does not duplicate an existing entry.

After Build starts, LLVM is not reselected or passed through build state. Existing tool usage remains ordinary:

  • cgo probes execute clang
  • IR checks execute llc
  • archive selection uses exec.LookPath("llvm-ar")
  • existing llvm.Env tool helpers retain their original behavior

Cross-compilation compilers and explicit overrides such as LLGO_AR retain their existing precedence.

Invocation isolation

  • Invocation contains only Args, Config, and Dir; it does not expose environment overrides
  • Config slices/maps are cloned before defaults are resolved
  • cwd and the process environment are captured once when Build starts
  • packages.Load and child commands receive explicit Dir/Env
  • relative outputs resolve against the invocation directory
  • NewDefaultConf no longer creates GOBIN; the linker creates the selected output directory on demand
  • no code under build.Do, Build, or package workers mutates process PATH
  • commandEnv is deliberately limited to cwd/env and is not an extension point for compiler state

Review size

  • base: current main at aa0bbe44
  • 18 files
  • +659 / -80
  • 1 commit

Tests

  • go test ./internal/build ./cmd/llgo ./xtool/env/llvm -count=1
  • focused invocation, command environment, cgo probe, emulator, and output-directory tests
  • the focused concurrency tests with -race
  • git diff --check

@fennoai fennoai Bot left a comment

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.

Review summary

Small, well-scoped foundational package (internal/processenv) capturing per-request process inputs (working dir + environment) with Abs/Get/Lookup helpers. The code is clean, go vet and go test ./internal/processenv/ pass, and the tricky clone/snapshot isolation is correctly implemented and tested. No blocking issues; two low-severity notes inline.

I verified the doc's Capture(dir, []string{}) promise empirically: slices.Clone([]string{}) returns a non-nil empty slice, so an explicitly-empty captured environment is correctly isolated and Lookup returns ("", false) without leaking the ambient environment. The doc/code match here — no change needed.

Minor (not blocking):

  • Lookup (processenv.go:73) does a linear reverse scan per call. Fine for typical low-frequency use; if a future hot-path caller resolves many keys against a large Env, consider building a one-time map (iterating forward to preserve last-wins).
  • processenv_test.go:1: the //go:build !llgo tag is unexplained — a one-line comment on why the tests are excluded under the llgo toolchain would help maintainers.

Comment thread internal/processenv/processenv.go Outdated

// Abs resolves path relative to the context working directory.
func (c Context) Abs(path string) string {
if path == "" || filepath.IsAbs(path) {

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.

Abs returns absolute inputs verbatim while relative inputs go through filepath.Join, which cleans them. So Abs("a/b/../c") is normalized but Abs("/a/b/../c") is not — inconsistent output for callers that expect a canonical path. If verbatim pass-through of absolute paths is intended, a one-line doc note would prevent surprise; otherwise consider filepath.Clean on the absolute branch.

Comment thread internal/processenv/processenv.go Outdated

// Get returns the last value for key in the context environment.
func (c Context) Get(key string) string {
if c.Env == nil {

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.

A zero Context{} (nil Env) transparently reads the live process environment via os.Getenv/os.LookupEnv, whereas a Captured context with an empty environment is isolated. So a zero-value Context is not an empty/isolated context — a subtle footgun once this package has real consumers. Worth documenting on the Context type that a nil Env means "defer to the live process environment."

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.23529% with 18 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/build/build.go 91.02% 6 Missing and 1 partial ⚠️
internal/build/cgo.go 73.07% 7 Missing ⚠️
internal/build/run.go 55.55% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@zhouguangyuan0718
zhouguangyuan0718 force-pushed the agent/build-isolation-01-context branch from d425493 to 03fa0a2 Compare July 29, 2026 15:27
@zhouguangyuan0718 zhouguangyuan0718 changed the title processenv: capture request process inputs build: bind LLVM tools without changing PATH Jul 29, 2026
@zhouguangyuan0718

Copy link
Copy Markdown
Contributor Author

I reworked this prerequisite after narrowing the concurrency contract. The previous processenv.Context/request-Env implementation has been removed entirely.

The new head addresses the actual production side effect directly: LLVM tools are bound to llvm-config --bindir, and the build no longer mutates process PATH. Non-LLVM tools keep normal host semantics. This reduces this PR to 119 changed lines and avoids promising per-build PATH replacement that go/packages cannot fully honor.

@zhouguangyuan0718 zhouguangyuan0718 changed the title build: bind LLVM tools without changing PATH build: isolate request configuration and execution Jul 29, 2026
@zhouguangyuan0718
zhouguangyuan0718 force-pushed the agent/build-isolation-01-context branch 4 times, most recently from a11308a to 287cbcc Compare July 30, 2026 14:37
@zhouguangyuan0718 zhouguangyuan0718 changed the title build: isolate request configuration and execution build: isolate invocation configuration and execution Jul 30, 2026
@zhouguangyuan0718
zhouguangyuan0718 force-pushed the agent/build-isolation-01-context branch from 287cbcc to 0f5fc99 Compare July 30, 2026 14:55
@xushiwei
xushiwei merged commit 9e8c827 into xgo-dev:main Jul 31, 2026
41 checks passed
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.

2 participants