Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Rationalize C compiler flags #3718

Closed
voodoos opened this issue Aug 18, 2020 · 11 comments · Fixed by #3875 or ocaml/opam-repository#17967
Closed

[RFC] Rationalize C compiler flags #3718

voodoos opened this issue Aug 18, 2020 · 11 comments · Fixed by #3875 or ocaml/opam-repository#17967
Assignees
Labels
proposal RFC's that are awaiting discussion to be accepted or rejected

Comments

@voodoos
Copy link
Collaborator

voodoos commented Aug 18, 2020

The present situation

In order to make things clearer I tried to retrace the processing of the C compilation flags, here is what I got:
(you can click to enlarge the image)

c_flags

Please tell me if I forgot something or misunderstood part of it.

What is wrong

  • ocamlc_cflags can end duplicated in the compiler command-line (if :standard was passed all the way down)
  • Dune silently adds ocamlc_cflags + ocamlc_cppflags to the command line making the :standard set of flags SC.default_c_cxx_flags irrelevant. This was unavoidable before because dune was calling ocamlc to compile C code.
  • The CC variable will always miss the ocamlc_cppflags and sometimes the ocamlc_cflags if the standard value was discarded, while these are in fact part of the compiler command line.

Proposition

Stop adding silently the flags from the config. These should be present in the :standard field and the users should be reminded that they need to use :standard when they want to add flags to the default set. This was not possible when dune was calling ocamlc to build C code but it is now that the C compiler is directly summoned.

This would solve the previous problem:

  • No more duplication of flags
  • The CC variable would really contain the base set of flags used for compiling
  • Users will be in total control of the flags set

The new flow would be:
new_c_flags

Of course this change will break some projects in which the :standard set of flags was overridden by the user. So we should add an option to the dune-project file for users that want to use the new system before 3.0.

@voodoos voodoos changed the title [RFC] C compiler flags [RFC] Rationalize C compiler flags Aug 18, 2020
@voodoos voodoos self-assigned this Sep 30, 2020
@voodoos voodoos added the proposal RFC's that are awaiting discussion to be accepted or rejected label Oct 1, 2020
@voodoos
Copy link
Collaborator Author

voodoos commented Oct 1, 2020

After discussing this proposal with @jeremiedimino an interrogation remained: what should the variable %{CC} contain ?

  • In current dune it may or may not contain flags from ocamlc_cflags depending on the use of :standard and user-defined flags in env stanzas. But may not reflect the base compiler command line because more flags are added at the last minute (ocamlc_cflags / cppflags).

  • In the proposal it would always reflect the "base" (without stub-specific flags) compiler command line used by dune to compile C stubs: cflags and cppflags depending on :standard use and environment-defined flags. Nothing is added silently.

We decided that the CC variable should behave as it does in other tools like auto-conf, however the manual is a bit confusing. @dra27, can you confirm whether or not the proposed behaviour is similar to the meaning of CC in autoconf ?

@samoht
Copy link
Member

samoht commented Oct 14, 2020

That seems like a very good proposal. For MirageOS we would like to cross-compile packages only using the flags declared in the current workspace context. A typical example would be:

(foreign_library
 (archive_name mirage-xen_bindings)
 (language c)
 (include_dirs ../include)
 (names main bmap evtchn gnttab
        alloc_pages_stubs atomic_stubs barrier_stubs checksum_stubs clock_stubs
        cstruct_stubs mm_stubs)
 (flags :standard -O2 -std=c99 -Wall -Werror
        -D__XEN_INTERFACE_VERSION__=__XEN_LATEST_INTERFACE_VERSION__))

Here :standard means: the C flags inherited from dune-worspace (which is initialised with pkg-config to get the correct flags). We really don't want to have the default flags from the OCaml compiler (e.g. we don't want -fPIC). So removing that magic addition of C flags is really critical for mirage.

The current workaround is to build the archive in a sandboxing build:

(env (_ (c_flags :standard -O2 -std=c99 -Wall -Werror
        -D__XEN_INTERFACE_VERSION__=__XEN_LATEST_INTERFACE_VERSION__)))

(rule
 (deps (source_tree .) (source_tree ../include))
 (targets mirage-xen-bindings.a)
 (action (run make CC=%{cc})))

But this needs we have to modify every foreign_library stanza to make that work (and thus we can't import foreign code). The envisaged workaround is to set-up a complete compiler toolchain in each different contexts, but that's a bit heavy-weight when the only necessary thing that we need is to change the C flags.

@voodoos
Copy link
Collaborator Author

voodoos commented Oct 14, 2020

@rgrinberg, do you agree that this proposal is an improvement on the current flags control ?

It should not necessitate a lot of changes now that Dune is calling the C compiler without the ocamlc proxy.
Of course it will break compatibility with users who didn't include the :standard set of flags when defining some c_flags.
We can either:

  • Limit the change to the next dune-lang version and users will need to update their (arguably wrong) files only if they want to update their dune lang version.
  • Make these changes opt-in via an option in the dune-project file, and make this new behavior (which appears more sane) default only in the next major dune version.

@mato
Copy link

mato commented Oct 14, 2020

But this needs we have to modify every foreign_library stanza to make that work (and thus we can't import foreign code). The envisaged workaround is to set-up a complete compiler toolchain in each different contexts, but that's a bit heavy-weight when the only necessary thing that we need is to change the C flags.

Just to add some context here: Having full control over what goes into the C compiler flags is only part of the solution. The larger issue stems from the somewhat arbitrary mixing of PIC and non-PIC C code, and the fact that shared objects are built unconditionally / foreign libraries are linked into .cmxs files. If it were possible to disable the latter on a case-by-case basis then I could just force PIC off with -fno-pic for the relevant libraries.

The only workaround which currently works without requiring any hacks or foreign library changes is to create a custom compiler variant where that compiler is configured with --disable-shared, which propagates down to dune nicely.

@rgrinberg
Copy link
Member

@voodoos this proposal looks good. Could also use this opportunity to standardize flag passing when compiling things with configurator?

@rgrinberg
Copy link
Member

@mato @samoht here's a related proposal that might help you guys out.

We really don't want to have the default flags from the OCaml compiler (e.g. we don't want -fPIC)

Makes sense. Would it also makes sense to modify this default set of flags?

The only workaround which currently works without requiring any hacks or foreign library changes is to create a custom compiler variant where that compiler is configured with --disable-shared, which propagates down to dune nicely.

That doesn't seem like a hack. It seems like there should be a way to set this option for any context from inside dune.

How about we make it possible to override the -config options for any context from inside dune? This could be done in the workspace file:

(context
 (default
  (config
   (supports_shared _libraries false))))

@voodoos
Copy link
Collaborator Author

voodoos commented Oct 19, 2020

@voodoos this proposal looks good. Could also use this opportunity to standardize flag passing when compiling things with configurator?

@rgrinberg I have very little knowledge on what dune configurator is doing, can you elaborate on that or give me some pointers ?

@rgrinberg
Copy link
Member

Binaries that use configurator also compile C sources with Configurator.V1.c_test and the like. It would be nice if these could use the same flags dune is using to compile executables in the same directory.

@mato
Copy link

mato commented Nov 9, 2020

I've tested #3875 against a version of mirage-xen with the Makefile-based build reverted (branch: https://github.com/mato/mirage-xen/tree/test-dune-cflags), and can confirm that it works as advertised.

However, it only solves part of the problem for Mirage, as the build breaks later when shared libraries are produced. To fix that, we indeed need something like what @rgrinberg mentioned in #3718 (comment).

Shall I create a separate issue to discuss that? If so, where?

@ghost
Copy link

ghost commented Nov 10, 2020

Creating a separate issue to discuss this seems good to me. We should always make sure we discuss one subject per issue/PR, to keep the discussion easy to follow.

@mato
Copy link

mato commented Nov 10, 2020

Creating a separate issue to discuss this seems good to me.

Done, #3934.

rgrinberg added a commit to rgrinberg/opam-repository that referenced this issue Jan 13, 2021
…ne-action-plugin, dune-private-libs and dune-glob (2.8.0)

CHANGES:

- `dune rules` accepts aliases and other non-path rules (ocaml/dune#4063, @mrmr1993)

- Action `(diff reference test_result)` now accept `reference` to be absent and
  in that case consider that the reference is empty. Then running `dune promote`
  will create the reference file. (ocaml/dune#3795, @bobot)

- Ignore special files (BLK, CHR, FIFO, SOCKET), (ocaml/dune#3570, fixes ocaml/dune#3124, ocaml/dune#3546,
  @ejgallego)

- Experimental: Simplify loading of additional files (data or code) at runtime
  in programs by introducing specific installation sites. In particular it allow
  to define plugins to be installed in these sites. (ocaml/dune#3104, ocaml/dune#3794, fixes ocaml/dune#1185,
  @bobot)

- Move all temporary files created by dune to run actions to a single directory
  and make sure that actions executed by dune also use this directory by setting
  `TMPDIR` (or `TEMP` on Windows). (ocaml/dune#3691, fixes ocaml/dune#3422, @rgrinberg)

- Fix bootstrap script with custom configuration. (ocaml/dune#3757, fixes ocaml/dune#3774, @marsam)

- Add the `executable` field to `inline_tests` to customize the compilation
  flags of the test runner executable (ocaml/dune#3747, fixes ocaml/dune#3679, @lubegasimon)

- Add `(enabled_if ...)` to `(copy_files ...)` (ocaml/dune#3756, @nojb)

- Make sure Dune cleans up the status line before exiting (ocaml/dune#3767,
  fixes ocaml/dune#3737, @alan-j-hu)

- Add `{gitlab,bitbucket}` as options for defining project sources with `source`
  stanza `(source (<host> user/repo))` in the `dune-project` file.  (ocaml/dune#3813,
  @rgrinberg)

- Fix generation of `META` and `dune-package` files when some targets (byte,
  native, dynlink) are disabled. Previously, dune would generate all archives
  for regardless of settings. (ocaml/dune#3829, ocaml/dune#4041, @rgrinberg)

- Do not run ocamldep to for single module executables & libraries. The
  dependency graph for such artifacts is trivial (ocaml/dune#3847, @rgrinberg)

- Fix cram tests inside vendored directories not being interpreted correctly.
  (ocaml/dune#3860, fixes ocaml/dune#3843, @rgrinberg)

- Add `package` field to private libraries. This allows such libraries to be
  installed and to be usable by other public libraries in the same project
  (ocaml/dune#3655, fixes ocaml/dune#1017, @rgrinberg)

- Fix the `%{make}` variable on Windows by only checking for a `gmake` binary
  on UNIX-like systems as a unrelated `gmake` binary might exist on Windows.
  (ocaml/dune#3853, @kit-ty-kate)

- Fix `$ dune install` modifying the build directory. This made the build
  directory unusable when `$ sudo dune install` modified permissions. (fix
  ocaml/dune#3857, @rgrinberg)

- Fix handling of aliases given on the command line (using the `@` and `@@`
  syntax) so as to correctly handle relative paths. (ocaml/dune#3874, fixes ocaml/dune#3850, @nojb)

- Allow link time code generation to be used in preprocessing executable. This
  makes it possible to use the build info module inside the preprocessor.
  (ocaml/dune#3848, fix ocaml/dune#3848, @rgrinberg)

- Correctly call `git ls-tree` so unicode files are not quoted, this fixes
  problems with `dune subst` in the presence of unicode files. Fixes ocaml/dune#3219
  (ocaml/dune#3879, @ejgallego)

- `dune subst` now accepts common command-line arguments such as
  `--debug-backtraces` (ocaml/dune#3878, @ejgallego)

- `dune describe` now also includes information about executables in addition to
  that of libraries. (ocaml/dune#3892, ocaml/dune#3895, @nojb)

- instrumentation backends can now receive arguments via `(instrumentation
  (backend <name> <args>))`. (ocaml/dune#3906, ocaml/dune#3932, @nojb)

- Tweak auto-formatting of `dune` files to improve readability. (ocaml/dune#3928, @nojb)

- Add a switch argument to opam when context is not default. (ocaml/dune#3951, @tmattio)

- Avoid pager when running `$ git diff` (ocaml/dune#3912, @AltGr)

- Add `(root_module ..)` field to libraries & executables. This makes it
  possible to use library dependencies shadowed by local modules (ocaml/dune#3825,
  @rgrinberg)

- Allow `(formatting ...)` field in `(env ...)` stanza to set per-directory
  formatting specification. (ocaml/dune#3942, @nojb)

- [coq] In `coq.theory`, `:standard` for the `flags` field now uses the
  flags set in `env` profile flags (ocaml/dune#3931 , @ejgallego @rgrinberg)

- [coq] Add `-q` flag to `:standard` `coqc` flags , fixes ocaml/dune#3924, (ocaml/dune#3931 , @ejgallego)

- Add support for Coq's native compute compilation mode (@ejgallego, ocaml/dune#3210)

- Add a `SUFFIX` directive in `.merlin` files for each dialect with no
  preprocessing, to let merlin know of additional file extensions (ocaml/dune#3977,
  @vouillon)

- Stop promoting `.merlin` files. Write per-stanza Merlin configurations in
  binary form. Add a new subcommand `dune ocaml-merlin` that Merlin can use to
  query the configuration files. The `allow_approximate_merlin` option is now
  useless and deprecated. Dune now conflicts with `merlin < 3.4.0` and
  `ocaml-lsp-server < 1.3.0` (ocaml/dune#3554, @voodoos)

- Configurator: fix a bug introduced in 2.6.0 where the configurator V1 API
  doesn't work at all when used outside of dune. (ocaml/dune#4046, @aalekseyev)

- Fix `libexec` and `libexec-private` variables. In cross-compilation settings,
  they now point to the file in the host context. (ocaml/dune#4058, fixes ocaml/dune#4057,
  @TheLortex)

- When running `$ dune subst`, use project metadata as a fallback when package
  metadata is missing. We also generate a warning when `(name ..)` is missing in
  `dune-project` files to avoid failures in production builds.

- Remove support for passing `-nodynlink` for executables. It was bypassed in
  most cases and not correct in other cases in particular on arm32.
  (ocaml/dune#4085, fixes ocaml/dune#4069, fixes ocaml/dune#2527, @emillon)

- Generate archive rules compatible with 4.12. Dune longer attempt to generate
  an archive file if it's unnecessary (ocaml/dune#3973, fixes ocaml/dune#3766, @rgrinberg)

- Fix generated Merlin configurations when multiple preprocessors are defined
  for different modules in the same folder. (ocaml/dune#4092, fixes ocaml/dune#2596, ocaml/dune#1212 and
  ocaml/dune#3409, @voodoos)

- Add the option `use_standard_c_and_cxx_flags` to `dune-project` that 1.
  disables the unconditional use of the `ocamlc_cflags` and `ocamlc_cppflags`
  from `ocamlc -config` in C compiler calls, these flags will be present in the
  `:standard` set instead; and 2. enables the detection of the C compiler family
  and populates the `:standard` set of flags with common default values when
  building CXX stubs. (ocaml/dune#3875, ocaml/dune#3802, fix ocaml/dune#3718 and ocaml/dune#3528, @voodoos)
NathanReb pushed a commit to NathanReb/ocaml-ctypes that referenced this issue Apr 14, 2022
This option (default in dune 3) is explained in
ocaml/dune#3718.
The reason it is necessary here is that `ocamlc_cflags` are added
without a way to override. Enabling this fixes the build on 32 bit
switches.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal RFC's that are awaiting discussion to be accepted or rejected
Projects
None yet
4 participants