n2 icon indicating copy to clipboard operation
n2 copied to clipboard

Path expansion in builds doesn't take take build variables in context

Open evmar opened this issue 3 years ago • 9 comments

In Ninja, the below refers to the file foo.3.

build foo.$bar: baz ...
  bar = 3

In n2 this doesn't. n2 aggressively expands variables while parsing, which is to say that in the above it never even generates intermediate data like the parse of foo.$bar, but rather expands $bar right as it sees it and then interns the path, and even reuses that buffer to parse/canonicalize the next path.

This is fixable but I'm kinda hesitant. To implement the Ninja behavior we'd instead need to build up an array of all the paths and then expand them once we've parsed through the variables. (Edit: another possibly costlier idea, we could skip forward to the variables, parse them, then go back and parse the paths again.)

The fact that builds seem to currently work suggests that maybe existing projects don't depend on this?

evmar avatar Apr 05 '22 07:04 evmar

For what it's worth, this was one of the two issues I faced in our build when trying to switch over to n2 from ninja. Our build generator would define things like $builddir at the top of build.ninja, and then in individual build steps, it would use variables that made use of them, eg out_dir = $builddir/some/path.

dae avatar Jun 15 '23 05:06 dae

Dang, that's a pretty strong argument that we ought to fix this. Unfortunately it will likely end up fairly costly. :( n2 is very aggressive about trying to do work incrementally to avoid needing to buffer stuff while parsing...

evmar avatar Jun 15 '23 06:06 evmar

Might be worth waiting around to see if anyone else hits this - it was fairly easy to work around in our case, and we may be an outlier. Doing a couple of string replacements in the build generator does seem to make more sense that pushing the work to build time.

dae avatar Jun 15 '23 06:06 dae

For what it's worth, this was one of the two issues I faced in our build when trying to switch over to n2 from ninja. Our build generator would define things like $builddir at the top of build.ninja, and then in individual build steps, it would use variables that made use of them, eg out_dir = $builddir/some/path.

Rereading this, I think this ought to be something that currently does work with n2. The specific issue here is instead about how in some (rare) cases Ninja variable expansion refers to a variable that it defined textually below where it's referenced, while n2 expands things roughly top-down. So I think that doesn't describe what you encountered.

evmar avatar Aug 29 '23 16:08 evmar

I might be missing something. Here's an example:

builddir = /home/dae/Local/build/anki
runner = $builddir/rust/release/runner

rule CargoBuild
  command = $runner run cargo build $release_arg $target_arg --locked $extra_args
  restat = 1
  hide_success = 1
  hide_last_line = 0

build  | $builddir/rust/debug/configure: CargoBuild  | .cargo/config.toml Cargo.lock build/configure/Cargo.toml build/configure/src/aqt.rs build/configure/src/bundle.rs build/configure/src/main.rs build/configure/src/platform.rs build/configure/src/pylib.rs build/configure/src/python.rs build/configure/src/rust.rs build/configure/src/web.rs build/ninja_gen/Cargo.toml build/ninja_gen/src/action.rs build/ninja_gen/src/archives.rs build/ninja_gen/src/build.rs build/ninja_gen/src/cargo.rs build/ninja_gen/src/command.rs build/ninja_gen/src/configure.rs build/ninja_gen/src/copy.rs build/ninja_gen/src/git.rs build/ninja_gen/src/hash.rs build/ninja_gen/src/input.rs build/ninja_gen/src/lib.rs build/ninja_gen/src/node.rs build/ninja_gen/src/protobuf.rs build/ninja_gen/src/python.rs build/ninja_gen/src/render.rs build/ninja_gen/src/rsync.rs build/ninja_gen/src/sass.rs build/runner/Cargo.toml build/runner/build.rs build/runner/src/archive.rs build/runner/src/build.rs build/runner/src/bundle/artifacts.rs build/runner/src/bundle/binary.rs build/runner/src/bundle/folder.rs build/runner/src/bundle/mod.rs build/runner/src/main.rs build/runner/src/paths.rs build/runner/src/pyenv.rs build/runner/src/rsync.rs build/runner/src/run.rs build/runner/src/yarn.rs rust-toolchain.toml
  configure = $builddir/rust/debug/configure
  description = build:configure_bin
  extra_args = -p configure
  release_arg = 
  target_arg = 

rule ConfigureBuild
  command = $runner run $cmd
  restat = 1
  generator = 1
  hide_success = 1
  hide_last_line = 0

build  | $builddir/build.ninja: ConfigureBuild  | $builddir/env $builddir/rust/debug/configure .git .version
  cmd = $builddir/rust/debug/configure
  description = build:configure

This fails with:

failed: build:configure
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: DidNotExecute { cmdline: "/rust/debug/configure", source: Os { code: 2, kind: NotFound, message: "No such file or directory" } }', build/runner/src/run.rs:86:30

dae avatar Aug 30 '23 00:08 dae

Thanks, opened https://github.com/evmar/n2/issues/83 about this one.

evmar avatar Aug 30 '23 06:08 evmar

(And now fixed, maybe.)

evmar avatar Aug 30 '23 19:08 evmar

Can confirm that's fixed it - thank you!

dae avatar Aug 30 '23 22:08 dae

This should be completed as of #94

Colecf avatar Jan 19 '24 19:01 Colecf