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] Relocation library #1185

Closed
ghost opened this issue Aug 28, 2018 · 20 comments · Fixed by ocaml/opam-repository#17967
Closed

[RFC] Relocation library #1185

ghost opened this issue Aug 28, 2018 · 20 comments · Fixed by ocaml/opam-repository#17967
Labels
accepted accepted proposals proposal RFC's that are awaiting discussion to be accepted or rejected

Comments

@ghost
Copy link

ghost commented Aug 28, 2018

It is common for programs to read configuration of data files installed on the system, for instance in /etc or /usr/share. In order for the program to find the files at runtime, it is common practice to capture an absolute path at configure time and store this path in the source code of the program.

There are two problems with this approach:

  • it is not clear how the program should find such files inside the project tests, i.e. before it is installed on the system
  • this doesn't play well when the binary artifacts are moved around. Systems that keep caches of built packages might do that for instance (esy, opam, ...)

The idea of this proposal is to provide a library so that programs can easily find such files without hassle. When running tests, dune would arrange things so that the paths reported by the library points to the local installation directory, i.e. _build/install. This library would also honor the environment variable from various systems (such as OPAM_SWITCH_PREFIX: ocaml/opam#3411) so that the binary artifacts can be easily relocated.

API

Here is a possible API for this library:

type path = string

val etc : unit -> path
val share : package:string -> path
...
@bobot
Copy link
Collaborator

bobot commented Aug 28, 2018

Frama-C get the location during tests of share using the environment variable FRAMAC_SHARE. With #680 and #205 this variable would be set automatically to the local directory.

However having a common library with the API given would factorize the work done by each tool, which is great.

User configuration directory could also be a good candidate (c.f https://github.com/gildor478/ocaml-xdg-basedir)

@ejgallego
Copy link
Collaborator

👍 for this; in Coq we have to use a very ugly set of heuristics due to this, moreover because we cannot depend on non-installed targets we must take into account placement into the build dir context.

@emillon
Copy link
Collaborator

emillon commented Dec 11, 2018

As discussed with @rgrinberg: it is possible to implement this using a global library, say dune.registry. This library embeds an absolute path that is generated at build time, and can be overridden at run time through environment variables.

The build time default corresponds to the dune install target directory. It will be possible to customize it by configuring --prefix through #1579, but this should already work without this.

At run time, we will be able to override this using the environment. The corresponding variables will be used by dune exec (and dune runtest) so that when running tests, the relocation directories will be resolved to local ones.

Variants might be helpful here, so that we can install a javascript version that points to local storage or similar instead of returning paths. Another interesting extension would be to add a crunch mode that returns the file contents instead of the path. It would need to read a string embedded into the resulting executable file.

@rgrinberg
Copy link
Member

We've discussed this further with @bobot, and there's a couple of more requirements:

  • When configuring to build dune itself, we want to be able to customize the relocation library. So for example, we want to be able to specify that the usr binary directory should be /usr/local/bin.

  • We want to be able to build "relocatable" binaries. These are binaries that lookup, etc, share, etc. relative to the binary's path.

@emillon
Copy link
Collaborator

emillon commented Dec 12, 2018

  • for the "default" installation prefix, do we need to support anything else besides /usr/local? it seems that make, for example, always defaults to this. /usr is reserved for the package manager, so it would be dangerous to have a dune-install version that defaults to this.
  • about relocatable binaries, I believe it's less important, but we should be able to solve that with a variant. I'm not sure how well it's possible to portably read the path of the binary. Also, in the context of a library that has data, should we detect the path of the binary or of the library?

@bobot
Copy link
Collaborator

bobot commented Dec 12, 2018

for the "default" installation prefix, do we need to support anything else besides /usr/local?

The opam default.

@rgrinberg
Copy link
Member

for the "default" installation prefix, do we need to support anything else besides /usr/local? it seems that make, for example, always defaults to this. /usr is reserved for the package manager, so it would be dangerous to have a dune-install version that defaults to this.

When we configure dune, the default for all of these should be the opam default I believe. So when we build dune with OPAM_SWITCH_PREFIX set, dune should prefer to install to that prefix.

@emillon
Copy link
Collaborator

emillon commented Dec 12, 2018

OK, works for me! I think that we have reached a nice consensus here :)

@emillon
Copy link
Collaborator

emillon commented Dec 12, 2018

I'll try to implement a first version of this.

@bobot
Copy link
Collaborator

bobot commented Jul 29, 2019

Contrary to what I implied with the reference, we can't use for the share directory the technique used for the version, because it should also work for dynamic libraries.

@nojb
Copy link
Collaborator

nojb commented Sep 8, 2019

What is the status of this PR ? Are there any blockers ?

@rgrinberg
Copy link
Member

rgrinberg commented Sep 9, 2019 via email

@jorsn
Copy link

jorsn commented Sep 12, 2020

TL;DR

The ability to set static paths at compile time is necessary, even if in some cases relocatability is desired:
This RFC provides no solution for systems like Nix where every package has its own prefix.
Also, it is probably easy to add this possibility, by adding an environment variable PREFIX to dune install and/or adding an option --prefix, env var PREFIX and dune var %{prefix} to the other dune commands, at least dune build.
Finally, this issue hasn't been resolved in two years, so there is probably the need for a simpler solution, instead of no solution at all.

Problem

Even if the proposed solution may be beneficial in many scenarios, it does not cover all that are relevant. The ability to set data or config paths at compile time is still necessary:

The solution still relies on the implicit information that there is one central prefix for everything. This is not always true. What about distros/package managers where every package has its own prefix, like Nix, Guix, GoboLinux, DJB's installation scheme, etc.?

It may be sometimes desirable to have relocatable executables, but not always. The mentioned package managers/distros (probably all, at least Nix, Guix) install immutable and immobile packages. Hence, relocatability provides no benefit, while the ability to hard-code directories at compile time makes things far easier: Everything is fixed at build time anyway, but runtime discoverability is really hard in these systems.

Of course one can wrap executables providing environment variables, but what if two used libs use two data/config files with the same name under two different prefixes? Then, even a *_PATH variable containing all data dirs in question as dir1:dir2:… wouldn't help.

By the way, e.g. the Nix community should be really relevant to dune: According to repology.org, it's the second largest linux distribution measured by the number of packages, and it's a community with a great affinity to functional programming.

Apart from the subject itself, AFAIK this RFC hasn't resulted in a pull request in two years, and the disability of reliably detecting any config/data paths resulted in multiple issues (at least #1253, #1534). Also, so far dune allows to detect and hardcode some installation paths, only not all consistently: You can e.g. execute opam config var prefix in your build, but you can't catch the --prefix option. According to the man page, you can set the DESTDIR as env var, but not the PREFIX.

Solution

I think, the simplest possible solution would be to make the inconsistent behavior consistent by adding a PREFIX environment variable which has the same meaning to dune install as the --prefix option (simple), and maybe by adding the --prefix option to all dune commands (kind of a general option of dune), together with a dune variable %{prefix}. Then, one can check PREFIX/%{prefix} in at least in every external command invoked by an action, e.g. in a configure script.

Alternative Solution

Implement config variables (#1579, #1674) and let prefix be such a config variable, respected by dune install.

@bobot
Copy link
Collaborator

bobot commented Sep 14, 2020

The MR #3104 merged not a long time ago tried to help in that direction. The feature added is experimental so it is time to ask for modifications.

The ability to set static paths at compile time is necessary, even if in some cases relocatability is desired:
This RFC provides no solution for systems like Nix where every package has its own prefix.

We use Nix for our CI, so I kept it in mind at first but since I haven't yet tested it in this environment I perhaps made mistakes. So I'm very happy that you reached us with this problem.

I haven't understood all the roadblock you described, to help that I will describe the features from #3104 that would help:

  • The currently undocumented environment variable DUNE_DIR_LOCATIONS, allows to give the site locations of a package PACKAGE:SITE:DIR:...
  • --prefix will install all the files in the given directory even for files installed into the directory of another package (e.g plugins )

Do you think those steps are in the right direction?

@jorsn
Copy link

jorsn commented Sep 18, 2020

@bobot So --prefix overrides defined sites? Is it possible to define the trivial site .? Or how is the installation prefix determined if --prefix is not set? Can one also query the sites as variables to run e.g. in an action

(action (with-stdout-to config.ml
    (echo "let data = "%{site share}/file.data"\n")))

? If yes, then this is basically what I propose, I think. If the sites can only be defined in the env var and not be queried as dune variable, then the config script can query them. This is the important half of my proposal.

@bobot
Copy link
Collaborator

bobot commented Sep 21, 2020

A better documentation and example is available in #3794.

So --prefix overrides defined sites? Or how is the installation prefix determined if --prefix is not set?

It does in the sense that when you install in the site of another package it will still be installed inside the --prefix provided. The prefix by default doesn't have any good value in Nix, except perhaps $out.

Can one also query the sites as variables to run e.g. in an action ?

Not in this form, because the sites is not the same between during the compilation/tests and after the installation, but the stanza generate_modules generate the code which provide this information.

This is the important half of my proposal.

Great. Can you test it in nix? One step I don't know exactly is if and which setupHook to use. Perhaps the nix dune package can create it so that the variable DUNE_DIR_LOCATIONS can be filled automatically. Perhaps dune install can install some specific files in $out that indicate what to append to DUNE_DIR_LOCATIONS in the nix setupHook.

@jorsn
Copy link

jorsn commented Sep 21, 2020

One question: How can a lib l reference its own site foo? By (site l foo)?

If I know this, I think I can try it out with Nix.

@bobot
Copy link
Collaborator

bobot commented Sep 21, 2020

Yes it is, in the install stanza. For example in the new examples.

@bobot
Copy link
Collaborator

bobot commented Nov 30, 2020

@jeremiedimino Do you think this feature is now fully implemented?

@ghost
Copy link
Author

ghost commented Nov 30, 2020

That's my understanding, yes. And if there are still details to sort out, let's rediscover them rather than keep this old issue.

I'm closing this issue then.

@ghost ghost closed this as completed Nov 30, 2020
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)
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted accepted proposals proposal RFC's that are awaiting discussion to be accepted or rejected
Projects
None yet
6 participants