Dune. Copy multiple dependencies to _build directory in `rule` stanza


I am developing a web server. Style sheets are written using SASS, and I want dune to process my .scss files to produce one .css file to be included in the resulting package.

Here is my dune file which tries to build a single .css file:

  (targets main.min.css)
        (:src ./stylesheets/main/main.scss)
        (:scss ./stylesheets))
  (action (run %{bin:scss} --load-path %{scss} %{src} %{targets})))

  (files (main.min.css as css/main.min.css))
  (section share)
  (package myserver))

scss binary need to know where to search for source files, and the directory with the sources is indicated under the --load-path argument. I am trying to pass this directory as a :scss dependency.

The output of dune build @install is:

Error: No rule found for dist/resources/css/stylesheets

where dist/resources/css is a directory containing dune file.

Seems that a directory cannot be a dependency in dune.
What should I do to copy necessary source files to _build directory before running an action defined in rule stanza?


You need to tell dune that you depend on all files in that directory:

  (targets main.min.css)
        (:src ./stylesheets/main/main.scss)
        (glob_files ./stylesheets/*))
  (action (run %{bin:scss} --load-path ./stylesheets %{src} %{targets})))

If you want to depend on all files recursively, you can use (source_tree stylesheets). However, this will only include files that are present in your source tree, i.e. not generated one. We don’t have yet a construction for depending on a files recursively including generated files, though we are planning to add support for that.


Thanks! That worked.
As I understood, glob_files is used to tell dune to depend on files in a certain directory, while source_tree is to tell dune to depend on all files in all subdirectories of specified path. Is that right?

BTW, is there any handy way to apply this rule to different targets? E.g. I want to compile different .css files with the same action, where only deps and targets are different, but the action is always the same.
Do I have to write single rule for every action of that kind or I can define something like a function for this?

Yes, that’s exactly that. Plus one more distinction: glob_files takes into account generated files but not source_tree. I guess source_tree is a bit odd and we should add something more generic that takes generated files into account, it’s just this way for historical reason.

Unfortinately yes. We are planning to add better support for such things in the future though. In the meantime, you can use the promotion feature to generate and commit the boilerplate. We do that in dune itself, in dune/doc:

(include dune.inc)

 (targets dune.inc.gen)
 (deps    (package dune))
  (with-stdout-to %{targets}
   (run bash %{dep:update-jbuild.sh}))))

 (name runtest)
 (action (diff dune.inc dune.inc.gen)))

Running dune runtest --auto-promote will update the dune.inc file in the source tree.