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.

1 Like

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.

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.