Exclude some dune rules from the default target

I’m trying to get dune to build some long-running tests only when I ask for it explicitly. I have a tests/ directory in which some short-running tests and some long-running tests reside. I can successfully call dune runtest to build the former ones.

To drive the long-running tests, I created a new alias and rules like so in tests/dune:

(alias (name longtest))
(rule 
  (deps)
  (action
    (with-stdout-to longtest1.output
      (run longtest --test1)))
(rule
  (alias longtest)
  (action (diff longtest1.expected longtest1.output)))

Now on dune build from a clean state, the long test runs. I then tried to remove the alias longtest from the default alias by prepending

(alias
  (name default)
  (deps (alias runtest)))

in tests/dune. I assumed this would instruct dune build to only build tests picked up by @runtest but not the long-running test. This did not appear to work. Where am I wrong?

In general I’m confused as to whether (alias (name x) (deps ...))) only adds new dependencies or redefines the set of dependencies for @x.

After some more poking around in the docs, I found no-infer. It appears that one cannot manually exclude a dependency once it has been inferred. an empty (deps) appears to do nothing.

But it’s possible to avoid picking up the dependency in the first place by using no-infer. I now have something like

(alias (name longtest))
(rule 
  (target longtest1.output)
  (action
    (no-infer
      (with-stdout-to longtest1.output
        (run longtest --test1))))
(rule
  (alias longtest)
  (action (diff longtest1.expected longtest1.output)))

So far this seems to run only if I call dune longtest explicitly and is skipped by dune build. I wonder if this is really the way it’s supposed to be done?

Hi!

I think that what’s happening is that when you attach a rule to @default in tests/, you’re overriding what dune does when dune build tests. But when running dune build (actually dune build .) it’s running the original default alias which is (alias_rec all) (see Default alias). So it will still try to build all the targets it knows of, including tests/longtest1.output, and this takes a long time (but note that it won’t try to run the actions associated to @longtest - the diff does not run).

I don’t think there’s a way to exclude a target from @all in dune at the moment.

Another remark:

(alias (name longtest))

This line can be omitted as it’s a no-op - aliases are implicitly declared.

2 Likes

that would suggest that i should actually try setting (alias all) in tests/dune. but you’re saying that @all is hardcoded, yes?

Yes. If I remember correctly, the “overriding” behavior only happens with default, not all.

1 Like

Thanks. It seems to me that wanting to exclude some targets from being built by dune build is not far-fetched? Then dune might want to allow this in some convenient way?

Aaics, now I could do (alias (name default) (deps (alias all))) non-recursively at the root and then in every subdirectory add the same definition, except for the tests/ subdirectory where I would maybe use (alias (name default) (deps (alias runtest))). Does that seem correct?

One could imagine dune defining instead (alias (name default) (deps (alias_rec local_default))) and then having some hardcoded rule that sets @local_default to @all in every subdirectory. This could then be overridden by users by setting @local_default to something other than all. It seems a bit hacky perhaps.

Now it got it. As the docs say, dune build is dune build @@default, where @@ instructs it to not descend into subdirectories. But the default definition of the default alias is (alias_rec all), which nevertheless will recursively descend into subdirectories, overriding @@, and build all everywhere. This seems a bit convoluted to me but explains what I have been seeing.

1 Like