# TIL: ghc-options: -O2 is a questionable practice

**URL:** <https://discourse.haskell.org/t/til-ghc-options-o2-is-a-questionable-practice/4812>\
**Category:** Learn\
**Created:** [July 21, 2022, 11:39am UTC](https://discourse.haskell.org/t/til-ghc-options-o2-is-a-questionable-practice/4812 "2022-07-21T11:39:27Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [July 21, 2022, 11:39am UTC](https://discourse.haskell.org/t/til-ghc-options-o2-is-a-questionable-practice/4812/1 "2022-07-21T11:39:27Z")

</div>

While browsing issues in the cabal github repository I encountered [this comment by Oleg Grengrus](https://github.com/haskell/cabal/issues/6221#issuecomment-526890087):

> [We] consider `ghc-options: -O2` (any -O flag) to be at the very least questionable practice.
> 
> In `cabal.project` you can have
> 
> ```haskell
> optimization: 2
> 
> ```
> 
> for all local, or per package (also non-local)
> 
> The core idea is that optimizations could be configured for all packages in an uniform way, without investigating if there’s some `dev`, `devel` or `fast` flag.
> 
> Also as a bonus, changing optimization level (also possible from command line), won’t cause full recompilation (or worse: mixed-level compilation) as build products are kept separate.

This was news to me, so I thought some people here could also benefit from seeing this.

---

<div class="post-metadata">

**Author:** ![anon58422685](https://avatars.discourse-cdn.com/v4/letter/a/67e7ee/32.png) [@anon58422685](https://discourse.haskell.org/u/anon58422685)\
**Post date:** [July 21, 2022, 2:14pm UTC](https://discourse.haskell.org/t/til-ghc-options-o2-is-a-questionable-practice/4812/2 "2022-07-21T14:14:13Z")

</div>

I do not get why this is a questionable practice.

I have a project that consists of a single Cabal package. In the Cabal manifest we have a flag `development` and some `common` stanza magic makes sure that all our code is built:

- With `-O2` when `development` is false.
- With `-O0` when `development` is true.

This gives us comfortable development experience, while we still deliver fast programs to our customers.

Is there something wrong with this setup? I understand that we can create two `cabal.project` files with different `optimization` but what good would it do in this setting?

---

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [July 21, 2022, 2:37pm UTC](https://discourse.haskell.org/t/til-ghc-options-o2-is-a-questionable-practice/4812/3 "2022-07-21T14:37:45Z")

</div>

> [@anon58422685](#):
>
> what good would it do in this setting?

One advantage of configuring it via `cabal.project` files is that your build products will be cached separately which means you won’t have to recompile everything when switching optimization levels:

> [@jaror](#):
>
> > Also as a bonus, changing optimization level (also possible from command line), won’t cause full recompilation (or worse: mixed-level compilation) as build products are kept separate.

Another advantage is that you don’t have to bother with cabal flags and common stanzas, but that is probably not a big problem for you. And I don’t know if the `cabal.project` approach is that much simpler.

---

<div class="post-metadata">

**Author:** ![anon58422685](https://avatars.discourse-cdn.com/v4/letter/a/67e7ee/32.png) [@anon58422685](https://discourse.haskell.org/u/anon58422685)\
**Post date:** [July 21, 2022, 3:35pm UTC](https://discourse.haskell.org/t/til-ghc-options-o2-is-a-questionable-practice/4812/4 "2022-07-21T15:35:06Z")

</div>

> [@jaror](#):
>
> your build products will be cached separately

How does this work? Does Cabal create different subdirectories of `dist-newstyle`, one for each `cabal.project` file? This problem can be solved with `git worktree` which economically creates another work tree for the same repository.

In my case, this problem is solved simply: continuous integration builds the executables for the customers, so I never have to switch the `development` flag off.

---

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [July 21, 2022, 5:36pm UTC](https://discourse.haskell.org/t/til-ghc-options-o2-is-a-questionable-practice/4812/5 "2022-07-21T17:36:39Z")

</div>

Yeah, it creates a new folder for each optimization level (not one for each cabal.project file).

In your situation it sounds the most sensible to me to have one `cabal.project` file that you use for CI and one that you use when developing (maybe a `cabal.project.local` for local development).

How do you manage your flags? If you use `cabal configure -f development` then you might as well just use `cabal configure --disable-optimization`, unless the development flag also does other things in addition to disabling optimizations.

---

<div class="post-metadata">

**Author:** ![anon58422685](https://avatars.discourse-cdn.com/v4/letter/a/67e7ee/32.png) [@anon58422685](https://discourse.haskell.org/u/anon58422685)\
**Post date:** [July 22, 2022, 4:19am UTC](https://discourse.haskell.org/t/til-ghc-options-o2-is-a-questionable-practice/4812/6 "2022-07-22T04:19:47Z")

</div>

Yes, it does. For development, we set:

- `ghc-options: -with-rtsopts=-N3` for executable stanzas so that running them leaves some CPU space for other things like HLS or background music.
- `ghc-options: -fdefer-typed-holes -Wtyped-holes` for all stanzas so that we can build and run stuff with holes.
- `cpp-options: -DDEVELOPMENT` for all stanzas so that the code itself knows which way it is built. _(Not sure if this is a good idea but it must have been needed for something.)_

However, we can still have all that by setting the flag appropriately in `cabal.project`.
