# Generating Makefiles with OCaml?

**URL:** <https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711>\
**Category:** Ecosystem\
**Tags:** build\
**Created:** [April 20, 2021, 8:37pm UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711 "2021-04-20T20:37:31Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![yawaramin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/yawaramin/32/3384_2.png) [@yawaramin](https://discuss.ocaml.org/u/yawaramin)\
**Post date:** [April 20, 2021, 8:37pm UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/1 "2021-04-20T20:37:31Z")

</div>

Has anyone ever tried to generate Makefiles for OCaml projects using OCaml itself?

I understand there have been all sorts of build tools and helpers, and there is now dune of course, but I’m wondering if anyone has had the idea to just codegen Makefiles? After all, OCaml is famous for symbolic manipulation. It should be (?) easy to generate a Makefile from a succinct project description written in OCaml. The benefit would be easy bootstrapping from a single script.

E.g., input:

```auto
(* proj.ml *)

open Makefile

make begin
  exe "main" [
    cmx "config" [];
    cmx "api" [
      cmx "config" [];
    ];
  ]
end

```

Output:

```auto
main.exe : config.cmx api.cmx main.cmx
    ocamlopt -o main.exe config.cmx api.cmx main.cmx

main.cmx : config.mli api.mli main.ml
    ocamlopt -c main.ml

config.cmi config.cmx : config.mli config.ml
    ocamlopt -c config.mli config.ml

api.cmi api.cmx : config.mli api.mli api.ml
    ocamlopt -c api.mli api.ml

```

This is of course a trivial example. Point is, OCaml is a great DSL to describe a build graph and generate a lower-level build file (Makefile, or even ninja file). E.g., you might have noticed a redundancy in the above OCaml snippet that we can factor out.

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [April 20, 2021, 9:32pm UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/2 "2021-04-20T21:32:56Z")

</div>

> [@yawaramin](#):
>
> Has anyone ever tried to generate Makefiles for OCaml projects using OCaml itself?

There was [GitHub - samoht/assemblage: A collection of tools to manage the configuration of OCaml projects](https://github.com/samoht/assemblage) at a time but as far as I know it never reached production quality.

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![Chet\_Murthy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chet_murthy/32/1501_2.png) [@Chet\_Murthy](https://discuss.ocaml.org/u/Chet_Murthy)\
**Post date:** [April 20, 2021, 11:44pm UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/3 "2021-04-20T23:44:21Z")

</div>

I don’t want to dissuade you, but … I actually doubt OCaml would be a good choice, b/c creating Makefiles involves so much string-manipulation, and OCaml isn’t good at that. If I were going to attack this problem, I’d try to build a MakeMaker (the perl equiv to what you seek) work-alike for OCaml.

The other place I might look is the OMake implementation (Ocaml implementation of make, but with added function). These days, maintained (IIRC) by Gerd Stolpmann (of findlib fame).

---

<div class="post-metadata">

**Author:** ![c-cube](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/c-cube/32/1727_2.png) [@c-cube](https://discuss.ocaml.org/u/c-cube)\
**Post date:** [April 21, 2021, 12:39am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/4 "2021-04-21T00:39:41Z")

</div>

If you insist on generating some build system, consider [ninja](https://ninja-build.org/) instead perhaps?  
It’s faster than Make and arguably simpler, too.

---

<div class="post-metadata">

**Author:** ![yawaramin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/yawaramin/32/3384_2.png) [@yawaramin](https://discuss.ocaml.org/u/yawaramin)\
**Post date:** [April 21, 2021, 1:04am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/5 "2021-04-21T01:04:35Z")

</div>

> [@Chet\_Murthy](#):
>
> I actually doubt OCaml would be a good choice, b/c creating Makefiles involves so much string-manipulation, and OCaml isn’t good at that.

I was thinking something specialized for OCaml, actually, so presumably there shouldn’t be that much string manipulation. Something much like Assemblage, actually, possibly simpler?

> [@c-cube](#):
>
> consider [ninja](https://ninja-build.org/) instead perhaps?  
> It’s faster than Make and arguably simpler, too.

It’s tempting but make is just so much more easily available that it’s probably a better target.

---

<div class="post-metadata">

**Author:** ![LdBeth](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/ldbeth/32/2680_2.png) [@LdBeth](https://discuss.ocaml.org/u/LdBeth)\
**Post date:** [April 21, 2021, 1:37am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/6 "2021-04-21T01:37:19Z")

</div>

Have a look at Haskell’s [Shake](https://ndmitchell.com/downloads/paper-shake_before_building-10_sep_2012.pdf), and [Build Systems à la Carte](https://www.microsoft.com/en-us/research/uploads/prod/2018/03/build-systems.pdf) for discuss about building systems in general.  
Instead of creating a Makefile, Shake produces an executable that directly calls the compiler via command line, in this way it is more efficient and not limited by the capability of `make` program.

---

<div class="post-metadata">

**Author:** ![Khady](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/khady/32/469_2.png) [@Khady](https://discuss.ocaml.org/u/Khady)\
**Post date:** [April 21, 2021, 2:34am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/7 "2021-04-21T02:34:51Z")

</div>

Dune has the ability to generate makefiles. `dune rules -m ./your/build/target`

---

<div class="post-metadata">

**Author:** ![rgrinberg](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/rgrinberg/32/40_2.png) [@rgrinberg](https://discuss.ocaml.org/u/rgrinberg)\
**Post date:** [April 21, 2021, 5:49am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/8 "2021-04-21T05:49:32Z")

</div>

It’s certainly doable, but what’s the point? Dune is a lighter dependency than make and only requires the OCaml compiler which is already necessary by your project. Make offers no performance advantage over dune either.

So it seems like a very challenging project (once you go beyond toy examples and start considering portability), with no benefit as far as I can see.

---

<div class="post-metadata">

**Author:** ![Chet\_Murthy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chet_murthy/32/1501_2.png) [@Chet\_Murthy](https://discuss.ocaml.org/u/Chet_Murthy)\
**Post date:** [April 21, 2021, 5:58am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/9 "2021-04-21T05:58:18Z")

</div>

I agree with @rgrinberg : if you’re going to start with OCaml datastructures, then you’re almost certainly not going to have the flexibility to express the stuff that Make does, that dune cannot. Might as well just use dune.

And I’m not even a dune user.

---

<div class="post-metadata">

**Author:** ![jhw](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jhw/32/1639_2.png) [@jhw](https://discuss.ocaml.org/u/jhw)\
**Post date:** [April 21, 2021, 10:04pm UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/10 "2021-04-21T22:04:08Z")

</div>

If we’re going to talk about alternatives to Dune, then I’d like to put in my request for better support for OCaml in Bazel. This is one of the few remaining things that keeps me from evangelizing OCaml as a language for off-robot applications at my day job.

---

<div class="post-metadata">

**Author:** ![kanishka](https://avatars.discourse-cdn.com/v4/letter/k/3e96dc/32.png) [@kanishka](https://discuss.ocaml.org/u/kanishka)\
**Post date:** [April 22, 2021, 12:31am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/11 "2021-04-22T00:31:26Z")

</div>

My impression is that dune is faster than bazel, while also being inspired by it. I haven’t run tests to verify this. For me, the main benefit of switching to bazel would be to keep learning a general purpose build system which I might use to compile code in other languages when necessary.

---

<div class="post-metadata">

**Author:** ![jhw](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jhw/32/1639_2.png) [@jhw](https://discuss.ocaml.org/u/jhw)\
**Post date:** [April 22, 2021, 1:06am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/12 "2021-04-22T01:06:42Z")

</div>

> [@kanishka](#):
>
> For me, the main benefit of switching to bazel would be to keep learning a general purpose build system which I might use to compile code in other languages when necessary.

If you don’t already have a big pile of Bazel on your hands, then I would say “Thank your lucky stars, and just use whatever you’re already using.” If it’s straight OCaml and nothing else, Dune is probably your friend. A highly opinionated friend, but a good friend. The only reason to consider alternatives to Dune is when you have a giant monorepository full of C++, Python, Rust, Go, and who knows what else, and it all has to go through a giant multiplatform build, integration and test system. And if that is what you’re doing, then OMG I hope you have a lot of whiskey on hand if you’re trying to do it with Makefiles.

---

<div class="post-metadata">

**Author:** ![rgrinberg](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/rgrinberg/32/40_2.png) [@rgrinberg](https://discuss.ocaml.org/u/rgrinberg)\
**Post date:** [April 22, 2021, 1:55am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/13 "2021-04-22T01:55:25Z")

</div>

It should be possible for dune to be helpful in this situation as well. In theory, there’s nothing difficult about dune generating functional, but highly ugly, and unportable bazel build files. Do bazel builds allow for a stage where rules are generated using an external tool?

---

<div class="post-metadata">

**Author:** ![jhw](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jhw/32/1639_2.png) [@jhw](https://discuss.ocaml.org/u/jhw)\
**Post date:** [April 22, 2021, 2:48am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/14 "2021-04-22T02:48:35Z")

</div>

> [@rgrinberg](#):
>
> Do bazel builds allow for a stage where rules are generated using an external tool?

No, and it’s _really quite opinionated_ on that point. Rules are written in Starlark period full stop, and Starlark isn’t Python because Python is too powerful for people entrusted to write `BUILD` and `*.bzl` files to be allowed to use it. And nobody complains to the Bazel gods about that, unless they want to be smitten down.

Bazel does allow you to call out to an external build system for constructing an imported package, and this is what [jin/rules\_ocaml](https://github.com/jin/rules_ocaml) does for building an external OPAM package, but it isn’t very robust at building an OCaml program from a list of `.ml` and `.mli` files— _that_ will fail in mysterious ways if you blow on it gently, i.e. try to build anything moderately complicated. See below.

A reason OCaml is difficult for Bazel is that OCaml is finicky about build order in ways that all the various languages Bazel likes— because G\*\*\*\*\* likes them and them alone— are not. The `ocamldep` tool produces information that Bazel quite deliberately refuses to give you an automatic way to use in feeding the dependency graph. It is a matter of principled design that Bazel insists you manually and explicitly specify all the dependencies in a rule and they are not automatically discovered. It looks at our `ocamldep` tool and raises its holy symbol and shouts in a broken dead language until it goes away.

As you might imagine, that makes compiling the `.cmi` and `.cmx` files for a library that has a complicated internal dependency graph currently discovered quietly and automatically by `ocamldep` a bit of a problem. Which basically means, that if you want a decent OCaml toolchain for use with Bazel, you have to wrap it somehow so that when you write something like this…

```auto
ocaml_native_library(
    name = "my_library",
    srcs = glob(["*.ml", "*.mli"]),
)

```

…the code for that rule compiles all the `.cmi`, `.cmx`, `.o` files, and everything else, in the right order— because Bazel isn’t going to help you by slurping the output of `ocamldep` into its dependency graph like other tools will do.

An additional complication is that when you provide a list of source files in a `srcs=[]` parameter to a rule, the convention is that the list is unordered, and conventionally many shops uses a Starlark formatter that automatically alphabetizes such lists and a commit guard on the repository that requires the `BUILD` files to be fed through the auto-formatter. Which means you can’t require the `srcs=[]` list to be specified in the correct build order for OCaml.

To do this right, you need to be very clever in the Starlark code that compiles a library or a program, more clever than anybody has yet tried to be. I don’t think I would try unless I was getting paid.

---

<div class="post-metadata">

**Author:** ![rgrinberg](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/rgrinberg/32/40_2.png) [@rgrinberg](https://discuss.ocaml.org/u/rgrinberg)\
**Post date:** [April 22, 2021, 3:08am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/15 "2021-04-22T03:08:55Z")

</div>

Writing OCaml build rules in crippled DSLs is something I’m very experienced in (Make, OMake), but I will have to pass on this opportunity. Somehow, reimplementing dune in skylark doesn’t sound very appealing.

I guess I was mostly inspired by blog posts like this one: [https://www.tweag.io/blog/2019-10-09-bazel-cabal-stack/](https://www.tweag.io/blog/2019-10-09-bazel-cabal-stack/). Substitute haskell for OCaml, and cabal for dune, and I thought we’d be in business.

---

<div class="post-metadata">

**Author:** ![LdBeth](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/ldbeth/32/2680_2.png) [@LdBeth](https://discuss.ocaml.org/u/LdBeth)\
**Post date:** [April 22, 2021, 4:15am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/16 "2021-04-22T04:15:40Z")

</div>

I think the key concern from OP is about using plain OCaml code to configure the project. So neither dune or OMake has provided this kind of possibilities yet. However providing a combinator style interface to these build systems seems appareling.

---

<div class="post-metadata">

**Author:** ![jhw](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jhw/32/1639_2.png) [@jhw](https://discuss.ocaml.org/u/jhw)\
**Post date:** [April 22, 2021, 5:14am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/17 "2021-04-22T05:14:39Z")

</div>

> [@rgrinberg](#):
>
> Substitute haskell for OCaml, and cabal for dune, and I thought we’d be in business.

You might be able to do that in some shops that use Bazel, i.e. substitute a) OCaml for Haskell, and b) Dune and OPAM for Cabal and Stack. In a shop like the one used at my day job, calling out to an external build tool for first-party code is just not done.

We have a lot of processes that are built around fine-grained analysis and management of the Bazel dependency graph. Bazel really shines for this, and it pushes you very hard to translate everything into Starlark so you can get those abilities. Anything that requires calling out to an external build system is a pain in the neck unless you’re okay with treating it like a black box.

And even then, did you look at the `bazel-tools` directory in that DAML repository? There’s a lot of clever logic going on in there, and it still walls giant masses of the dependency graph off where Bazel can’t see it except as big blobs dependent on other big blobs.

---

<div class="post-metadata">

**Author:** ![orbitz](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/orbitz/32/110_2.png) [@orbitz](https://discuss.ocaml.org/u/orbitz)\
**Post date:** [April 22, 2021, 2:44pm UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/18 "2021-04-22T14:44:42Z")

</div>

[pds](https://hg.sr.ht/~mmatalka/pds) generates makefiles but not in this way, it just uses a pretty simple templating language to spit them out.

---

<div class="post-metadata">

**Author:** ![jhw](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jhw/32/1639_2.png) [@jhw](https://discuss.ocaml.org/u/jhw)\
**Post date:** [April 23, 2021, 6:25pm UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/19 "2021-04-23T18:25:47Z")

</div>

> [@rgrinberg](#):
>
> Substitute haskell for OCaml, and cabal for dune, and I thought we’d be in business.

I don’t want to flog a dead ungulate, but I found this page about Bazel Rules for Haskell [Is Bazel right for me? — rules\_haskell documentation](https://rules-haskell.readthedocs.io/en/latest/why-bazel.html) and I found it really informative and wanted to add it here in case anyone cares. I looked at the code this is documenting, and it’s basically what I wish existed for OCaml. Not enough to write it myself today, but enough to hope someone else does before I have a real need for it.

---

<div class="post-metadata">

**Author:** ![jeremiedimino](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jeremiedimino/32/699_2.png) [@jeremiedimino](https://discuss.ocaml.org/u/jeremiedimino)\
**Post date:** [April 26, 2021, 8:44am UTC](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711/20 "2021-04-26T08:44:48Z")

</div>

> [@yawaramin](#):
>
> Has anyone ever tried to generate Makefiles for OCaml projects using OCaml itself?

Dune started as a makefile generator.

I wrote an OCaml program that was generating a Makefile for the [Base library](https://opensource.janestreet.com/base/) about 5 years ago. I then extended it to build more packages and after several months of work it became Jbuilder. It was a standalone tool that could build all Jane Street packages. Jbuilder then became Dune with the help of the community.

The original code of this Makefile generator can be found [here](https://github.com/janestreet/base/blob/05a3cdc443258e3e586c1bb9ac565836e9236a06/build/gen_rules.ml). The Dune repository still has a file called [gen\_rules.ml](https://github.com/ocaml/dune/blob/main/src/dune_rules/gen_rules.ml) today.

[Next page](https://discuss.ocaml.org/t/generating-makefiles-with-ocaml/7711.md?page=2)
