Dune - how to link statically on Linux, not on others?

Questions about static linking have come up in the past. What is the current best practice to support that conditionally on Linux but not other platforms? The easiest way to link a binary statically is to add

(link_flags (:standard -cclib -static))

to an executable stanza. Is it possible to add this conditionally? Or is it better to organise this in some profile?

2 Likes

Yes, you can use something like this:

(rule (with-stdout-to link_flags.Unix (echo "(-cclib -static)")))

(rule (with-stdout-to link_flags.Win32 (echo "()")))

(executable ...
 (link_flags (:include link_flags.%{os_type})))

You could use a different variable or combination of variables instead of %{os_type} depending on what you want to take into consideration for choosing your flags (system, compiler, etc).

Cheers,
Nicolas

6 Likes

Small wrinkle in this solution: %{os_type} is Unix on macOS where -cclib -static does not work.

3 Likes

Yes, the difficulty in differentiating between Linux and macOS is a long standing issue.
The more general solution is to write a small script (eg in OCaml) that outputs the right links flags for the current system:

(rule (with-stdout-to link_flags.sexp (run %{ocaml} %{dep:gen_link_flags.ml})))

(executable ...
 (link_flags (:include link_flags.sexp)))

In your script gen_link_flags.ml you are free to call uname or whathaveyou to output the right flags.

Cheers,
Nicolas

4 Likes

For anyone interested in the detection part of this, Revery has some code to detect the host OS which I’ve also used in OCaml syntax. It’s worked for me on Linux, macOS and Windows.

2 Likes

awesome, led me to use a dash script

#!/bin/sh
# https://discuss.ocaml.org/t/dune-how-to-link-statically-on-linux-not-on-others/8537/4?u=mro

case "$(uname -s)" in
  Darwin)
    # do not link statically on macos.
    echo '()'
    ;;
  *)
    echo '(-ccopt "-static")'
    ;;
esac

had postponed that ever since and resolved now, thanks @lindig, @nojb

1 Like

Here’s another way @mro, with no shell script required. :slight_smile:

Using the system variable is a bad idea as explained in Get the `system` variable to be consistent · Issue #10613 · ocaml/ocaml · GitHub

2 Likes

You can use

(rule (with-stdout-to link_flags.linux (echo "(-cclib -static)")))

(rule (with-stdout-to link_flags.macosx (echo "()")))


(executable ...
 (link_flags (:include link_flags.%{system})))