gasche / manual-ocamlbuild

A new reference manual for the ocamlbuild tool
Other
67 stars 15 forks source link

how to create files outside of _build #21

Open agarwal opened 8 years ago

agarwal commented 8 years ago

I'm writing a rule like this:

rule ".merlin"
  ~prod:".merlin"
  (fun env _ -> Echo (["S ./src/**"], ".merlin"))

which produces the file _build/.merlin, but we want .merlin in the root of our repo. I tried using Pathname.pwd but that doesn't seem to help. I'm also not using env, but AFAICT that only expands variable names so it isn't relevant.

(I realize my issues are questions, but hopefully they suggest documentation improvements so are relevant to this repo.)

gasche commented 8 years ago

Pathname.pwd is the project path, how does it not work for you? Note that ocamlbuild is designed to only write files in the build directory, not in the source directory, except for explicitly named targets for which links in the source directory are created. You have the expressive power to get out of that model (define a rule "project files" that creates a fixed list of files in _build and links them in the source directory¹), but this should be done rather carefully.

¹: I think it is better to create in the build dir and then link than to create in pwd directly, because ocamlbuild will look in the build dir to see if the target has already been built, etc.

agarwal commented 8 years ago

Pathname.pwd is the project path, how does it not work for you?

I set ~prod to Filename.concat Pathname.pwd ".merlin", thinking that I'm now specifying an absolute path, so that maybe ocamlbuild would disregard _build. However, it doesn't recognize the request at all now.

$ ocamlbuild .merlin
Finished, 1 target (0 cached) in 00:00:00.
Solver failed:
  Ocamlbuild knows of no rules that apply to a target named .merlin. This can happen if you ask Ocamlbuild to build a target with the wrong extension (e.g. .opt instead of .native) or if the source files live in directories that have not been specified as include directories.
Compilation unsuccessful after building 0 targets (0 cached) in 00:00:00.
agarwal commented 8 years ago

Trying your suggestion to define a "project files" rule, I have this:

$ cat myocamlbuild.ml 
open Ocamlbuild_plugin

let () = dispatch (function
  | After_rules -> (
    rule ".merlin"
      ~prod:".merlin"
      (fun env _ -> Echo (["S ./src/**"], ".merlin"))
    ;

    rule "project files"
      ~stamp:"project_files.stamp"
      (fun _ build ->
    let project_files = [[".merlin"]] in
    List.map Outcome.good (build project_files) |>
    List.map (fun result ->
      Cmd (S [A "ln"; A "-sf";
          P (!Options.build_dir/result);
          P Pathname.pwd] )
    ) |>
    fun l -> Seq l
      )
  )
  | _ -> ()
)

The "project files" rule has no prod, so how do you invoke it? Doing ocamlbuild .merlin only produces _build/.merlin, and understandably not the link that "project files" creates.

agarwal commented 8 years ago

You have the expressive power to get out of that model

Building in _build is of course good; it should be the default but I shouldn't be disallowed from creating a file elsewhere. Your suggestion to link files is a hack because the link isn't a first class entity of the build DAG.

A better solution would be: relative paths should by default be assumed to be relative to _build, but it should be possible to give repo_root as an alternative.

agarwal commented 8 years ago

I still don't know how to invoke the "project rules" rule, so I thought a workaround is to do ocamlbuild .merlin. I thought explicit targets to ocamlbuild are symlinked, but no symlink is created in this case. This doesn't work for cma's either so perhaps the automatic linking is only done for executables, which would actually make sense.

gasche commented 8 years ago

I thought I had answered already, sorry. Just request the stamp as target: ocamlbuild project_files.stamp will run the rule.

(Yes, automatic linking is kind of flaky right now, and I'm not sure exactly how to specify it and whether making it more uniform is a good idea.)

agarwal commented 8 years ago

Thanks. I thought I had tried that, but must have done something wrong. This works.

Another thing I noticed is that one cannot create the symlink and git commit it because ocamlbuild deletes the symlink!