# Dune build vs Makefile

**URL:** https://discuss.ocaml.org/t/dune-build-vs-makefile/11394
**Category:** Learning
**Created:** [February 10, 2023, 10:45pm UTC](https://discuss.ocaml.org/t/dune-build-vs-makefile/11394 "2023-02-10T22:45:38Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![zeroexcuses](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/zeroexcuses/32/1692_2.png) [@zeroexcuses](https://discuss.ocaml.org/u/zeroexcuses)
#### Post date: [February 10, 2023, 10:45pm UTC](https://discuss.ocaml.org/t/dune-build-vs-makefile/11394/1 "2023-02-10T22:45:38Z")

</div>

I am trying to figure out this 10x difference.

```auto
time dune build @app
                                   
real	0m9.143s
user	0m8.279s
sys	0m0.883s

```

vs

```auto
 time make
ocamlfind ocamlc -g -linkpkg -package brr min.ml
js_of_ocaml a.out -o min.js

real	0m0.665s
user	0m0.606s
sys	0m0.059s

```

These are both incremental builds.

```auto
cat bin/dune ; echo "===="; cat Makefile ; 
(executables
  (names min)
  (libraries brr)
  (modes js))

(rule
  (targets min.js)
  (deps min.bc.js)
  (action (run cp %{deps} %{targets})))

(alias
  (name app)
  (deps min.js ))

====
build:
	ocamlfind ocamlc -g -linkpkg -package brr min.ml
	js_of_ocaml a.out -o min.js

fancy_console:
	ocamlfind ocamlc -g -linkall -linkpkg -package brr,brr.poked min.ml
	js_of_ocaml $(ocamlfind query -r -i-format brr.poked) -I . \
		--toplevel a.out -o min.js

.PHONY: build fancy_console

```

the min.ml consists of:

line 0: `open Brr`  
line 1-1001: repeated 1000 times: `let () = El.set_children (Document.body G.document) El.[txt' "Hello World!"]`

===

Question

1. what is the difference between “dune build @app” and “make” ?

2. for tooling reasons, I’d prefer to make the `dune build @app` faster – how do I do that ?

---

<div class="post-metadata">

### Author: ![dbuenzli](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dbuenzli/32/18_2.png) [@dbuenzli](https://discuss.ocaml.org/u/dbuenzli)
#### Post date: [February 10, 2023, 11:05pm UTC](https://discuss.ocaml.org/t/dune-build-vs-makefile/11394/2 "2023-02-10T23:05:04Z")

</div>

It’s not clear what you are measuring but I assume that’s cold builds.

Someone more versed into `dune`’s `js_of_ocaml` compilation strategy may offer better answers but the explanations must be along this:

> [@zeroexcuses](#):
>
> what is the difference between “dune build @app” and “make” ?

This invokes your build in `--profile=dev`. With this profile dune does separate JavaScript compilation.

This entails compiling bytecode library archives (the `.cma` files of the libraries you use) of each of the libraries you use in your program to separate JavaScript files. You’ll pay for that only once on cold builds or when you upgrade your library dependencies.

That’s long because you also end up compiling code you won’t use (there’s a lot of stuff in `brr.cma`). That’s not the case if you first link your bytecode with the `.cma` files perform dead code elimination and then compile to JavaScript.

If you prefer the latter you should compile with `--profile=release` (I don’t know if it’s possible to enable or disable separate compilation in `dev` mode, consult the `dune` manual).

> [@zeroexcuses](#):
>
> for tooling reasons, I’d prefer to make the `dune build @app` faster – how do I do that ?

Use `--profile=release` however when your app grows the numbers are going to turn upside down for incremental builds.

---

<div class="post-metadata">

### Author: ![zeroexcuses](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/zeroexcuses/32/1692_2.png) [@zeroexcuses](https://discuss.ocaml.org/u/zeroexcuses)
#### Post date: [February 10, 2023, 11:16pm UTC](https://discuss.ocaml.org/t/dune-build-vs-makefile/11394/3 "2023-02-10T23:16:21Z")

</div>

> [@dbuenzli](#):
>
> It’s not clear what you are measuring but I assume that’s cold builds.

No, (assuming I’m doing everything right) these are incremental builds.

1. build

2. insert a “\n” in the middle of min.ml

3. rebuild

---

<div class="post-metadata">

### Author: ![dbuenzli](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dbuenzli/32/18_2.png) [@dbuenzli](https://discuss.ocaml.org/u/dbuenzli)
#### Post date: [February 10, 2023, 11:34pm UTC](https://discuss.ocaml.org/t/dune-build-vs-makefile/11394/4 "2023-02-10T23:34:06Z")

</div>

Then I think `dune` also automatically generate source maps. Check out your build log you likely don’t have the same invocation as in your `Makefile`.

---

<div class="post-metadata">

### Author: ![edwin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/edwin/32/627_2.png) [@edwin](https://discuss.ocaml.org/u/edwin)
#### Post date: [February 10, 2023, 11:37pm UTC](https://discuss.ocaml.org/t/dune-build-vs-makefile/11394/5 "2023-02-10T23:37:06Z")

</div>

> [@dbuenzli](#):
>
> This invokes your build in `--profile=dev`. With this profile dune does separate JavaScript compilation.

Indeed, and the manual claims this is faster: [JavaScript Compilation With Js\_of\_ocaml — Dune documentation](https://dune.readthedocs.io/en/stable/jsoo.html#separate-compilation).  
However in the case of javascript (at least for small examples like this) that is clearly not true, because in dev mode I get a 2.3MB .js file, whereas in release mode a 61KB one, and producing the latter is a lot less work:

```auto
Summary
  'dune build --profile=release @app' ran
    9.20 ± 0.38 times faster than 'dune build --profile=dev @app'

```

There is a flag to force whole program mode for js\_of\_ocaml, but that is still slow (probably due to lack of dead code elimination, still produces a 512KB js file):

```auto
(env
  (dev (js_of_ocaml (compilation_mode whole_program))))

```

The dev profile also has other things like source maps and pretty printed output enabled, the release build doesn’t (you can see exactly what it does with `--verbose`).

If you add the following to your dune file it’ll speed it up considerably, however you’ll lose the source map:

```auto
(env
  (dev (js_of_ocaml
         (flags (:standard --no-source-map))
         (compilation_mode whole_program)
         )))

```

---

<div class="post-metadata">

### Author: ![zeroexcuses](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/zeroexcuses/32/1692_2.png) [@zeroexcuses](https://discuss.ocaml.org/u/zeroexcuses)
#### Post date: [February 10, 2023, 11:43pm UTC](https://discuss.ocaml.org/t/dune-build-vs-makefile/11394/6 "2023-02-10T23:43:05Z")

</div>

Confirming this dropped my incremental `dune build @app` down to Makefile levels:

```auto
 time dune build @app
                                  
real	0m0.892s
user	0m0.785s
sys	0m0.104s

```

---

<div class="post-metadata">

### Author: ![zeroexcuses](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/zeroexcuses/32/1692_2.png) [@zeroexcuses](https://discuss.ocaml.org/u/zeroexcuses)
#### Post date: [February 10, 2023, 11:50pm UTC](https://discuss.ocaml.org/t/dune-build-vs-makefile/11394/7 "2023-02-10T23:50:45Z")

</div>

I have a dumb followup question that I don’t understand.

1. with source map: 9+ seconds, w/o source map: \< 1 second

2. source map is just a giant hashmap mapping lines of js to line of ocaml right ?

3. our program is only 1000 lines of ocaml; why is this tiny sourcemap (hash table) adding 8 seconds, taking build time from \< 1 sec to \> 9 secs ?

---

<div class="post-metadata">

### Author: ![hhugo](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/hhugo/32/1143_2.png) [@hhugo](https://discuss.ocaml.org/u/hhugo)
#### Post date: [February 11, 2023, 9:32am UTC](https://discuss.ocaml.org/t/dune-build-vs-makefile/11394/8 "2023-02-11T09:32:54Z")

</div>

- Sourcemap rely on ocaml debug info, processing the additional info take some extra time, but it’s not the culprit here.
- When sourcemap is enabled, as a way to preserve more locations, jsoo put each function call in its own node in the control flow graph and I believe that your artificial example is hitting some quadratic algorithm. It depends on the number of function call inside a single function.
- It’s not clear that it affect real program that much but free to open an issue [Issues · ocsigen/js\_of\_ocaml · GitHub](https://github.com/ocsigen/js_of_ocaml/issues)

---

<div class="post-metadata">

### Author: ![hhugo](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/hhugo/32/1143_2.png) [@hhugo](https://discuss.ocaml.org/u/hhugo)
#### Post date: [February 11, 2023, 10:05am UTC](https://discuss.ocaml.org/t/dune-build-vs-makefile/11394/9 "2023-02-11T10:05:20Z")

</div>

I’ve a quick fix in [Compiler: no longer split blocks at fun call to propagate location by hhugo · Pull Request #1407 · ocsigen/js\_of\_ocaml · GitHub](https://github.com/ocsigen/js_of_ocaml/pull/1407). With your example, compilation time is around ~0.5s. I need to check that the generated sourcemap has the same amount of information. (Edit: need more work to preserve all the sourcemap info)
