diff --git a/doc/how-to-build-like-nix.rst b/doc/how-to-build-like-nix.rst index 9377cc94327..4889b0f95aa 100644 --- a/doc/how-to-build-like-nix.rst +++ b/doc/how-to-build-like-nix.rst @@ -1,45 +1,10 @@ .. _nix-style-builds: -How to build locally like in Nix -================================ - -Nix-style local builds are a new build system implementation inspired by Nix. -The Nix-style local build system is commonly called "v2-build" for short -after the ``cabal v2-*`` family of commands that control it. However, those -names are only temporary now that Nix-style local builds have become the -default. For those who do not wish to use the new -functionality, the classic project style will not be removed immediately, -but these legacy commands will require the usage of the ``v1-`` prefix as of -Cabal 3.0 and will be removed in a future release. For a future-proof -way to use these commands in a script or tutorial that anticipates the -possibility of another UI paradigm being devised in the future, there -are also ``v2-`` prefixed versions that will reference the same functionality -until such a point as it is completely removed from Cabal. - -Nix-style local builds combine the best of non-sandboxed and sandboxed Cabal: - -1. Like sandboxed Cabal previously, we build sets of independent local - packages deterministically and independent of any global state. - v2-build will never tell you that it can't build your package - because it would result in a "dangerous reinstall." Given a - particular state of the Hackage index, your build is completely - reproducible. For example, you no longer need to compile packages - with profiling ahead of time; just request profiling and v2-build - will rebuild all its dependencies with profiling automatically. - -2. Like non-sandboxed Cabal today, builds of external packages are - cached in a global store, so that a package can be built once, - and then reused anywhere else it is also used. No need to continually - rebuild dependencies whenever you make a new sandbox: dependencies - which can be shared, are shared. - -Nix-style local builds were first released as beta in cabal-install 1.24. -They currently work with all versions of GHC supported by that release: GHC 7.0 and later. - -Some features described in this manual are not implemented. If you need -them, please give us a shout and we'll prioritize accordingly. - +How to build packages +===================== +The following sections describe how to build and work with a package +or a project consisting of multiple packages. .. toctree:: nix-local-build diff --git a/doc/nix-local-build.rst b/doc/nix-local-build.rst index 6144cea85ba..6772993a7e0 100644 --- a/doc/nix-local-build.rst +++ b/doc/nix-local-build.rst @@ -4,10 +4,10 @@ Quickstart ========== Suppose that you are in a directory containing a single Cabal package -which you wish to build (if you haven't set up a package yet check -out :doc:`How to package Haskell code ` for -instructions). You can configure and build it using Nix-style -local builds with this command (configuring is not necessary): +which you wish to build (if you haven't set up a package yet check out +:doc:`How to package Haskell code ` for +instructions). You can configure and build it with this command +(configuring is not necessary): :: @@ -23,14 +23,14 @@ To run an executable defined in this package, use this command: :: - $ cabal run [executable args] + $ cabal run -- [executable args] Developing multiple packages ---------------------------- Many Cabal projects involve multiple packages which need to be built together. To build multiple Cabal packages, you need to first create a -``cabal.project`` file which declares where all the local package +:doc:`cabal.project ` file which declares where all the local package directories live. For example, in the Cabal repository, there is a root directory with a folder per package, e.g., the folders ``Cabal`` and ``cabal-install``. The ``cabal.project`` file specifies each folder as @@ -77,11 +77,7 @@ example, to build a test suite named ``package-tests``, use the command: Targets can be qualified with package names. So to request ``package-tests`` *from* the ``Cabal`` package, use -``Cabal-tests:package-tests``. - -Unlike sandboxes, there is no need to setup a sandbox or ``add-source`` -projects; just check in ``cabal.project`` to your repository and -``build`` will just work. +``Cabal:package-tests``. Cookbook ======== @@ -137,13 +133,17 @@ development environments. How it works ============ +The following sections are intended to provide you with a mental model +for how building works: where dependencies are fetched from, where +build products are stored, and what state (if any) is affected by +performing actions with Cabal. + Local versus external packages ------------------------------ -One of the primary innovations of Nix-style local builds is the -distinction between local packages, which users edit and recompile and -must be built per-project, versus external packages, which can be cached -across projects. To be more precise: +Cabal distinguishes between local packages, which users edit and +recompile and must be built per-project, and external packages, which +can be cached across projects. To be more precise: 1. A **local package** is one that is listed explicitly in the ``packages``, ``optional-packages`` or ``extra-packages`` fields of a @@ -151,11 +151,12 @@ across projects. To be more precise: source code stored in a folder in your project, while ``extra-packages`` lists packages residing on Hackage that are treated as being local anyway. -Local packages, as well as the external packages (below) which depend on -them, are built **inplace**, meaning that they are always built -specifically for the project and are not installed globally. Inplace -packages are not cached and not given unique hashes, which makes them -suitable for packages which you want to edit and recompile. +Local packages, as well as the external packages (below) which depend +on them, are built **in-place**, meaning that they are always built +locally for the project, and not installed in the global store (see +below). In-place packages are not cached and not given unique hashes, +which makes them suitable for packages which you want to edit and +recompile. 2. An **external package** is any package which is not listed in the ``packages``, ``optional-packages`` and ``extra-packages`` fields. @@ -165,7 +166,7 @@ When an external package does not depend on an inplace package, it can be built and installed to a **global** store, which can be shared across projects. These build products are identified by a hash based on all of the inputs which influence the compilation of a package (flags, -dependency selection, etc.). Just as in Nix, these hashes uniquely +dependency selection, etc.). These hashes uniquely identify the result of a build; if we compute this identifier and we find that we already have this ID built, we can just use the already built version. @@ -177,71 +178,50 @@ whatever reason (e.g., to reclaim disk space or because the global store is corrupted), deleting this directory is safe (``build`` will just rebuild everything it needs on its next invocation). -This split motivates some of the UI choices for Nix-style local build +This split motivates some of the UI choices for Cabal's build commands. For example, flags passed to ``cabal build`` are only applied to *local* packages, so that adding a flag to ``cabal build`` doesn't necessitate a rebuild of *every* transitive dependency in the global package store. -In cabal-install 2.0 and above, Nix-style local builds also take advantage of a -new Cabal library feature, `per-component -builds `__, -where each component of a package is configured and built separately. -This can massively speed up rebuilds of packages with lots of components -(e.g., a package that defines multiple executables), as only one -executable needs to be rebuilt. Packages that use Custom setup scripts -are not currently built on a per-component basis. +When a package has multiple components (libraries, executables, etc.), +each component is configured and built separately. This can massively +speed up rebuilds of packages with lots of components (e.g., a package +that defines multiple executables), as only one executable needs to be +rebuilt. Packages that use Custom setup scripts (see +:ref:`more-complex-packages`) are not currently built on a +per-component basis. Where are my build products? ---------------------------- -A major deficiency in the current implementation of ``cabal build`` is that -there is no programmatic way to access the location of build products. -The location of the build products is intended to be an internal -implementation detail of ``cabal build``, but we also understand that many -unimplemented features can only be reasonably worked around by -accessing build products directly. - -The location where build products can be found varies depending on the -version of cabal-install: - -- In cabal-install-1.24, the dist directory for a package ``p-0.1`` is - stored in ``dist-newstyle/build/p-0.1``. For example, if you built an - executable or test suite named ``pexe``, it would be located at - ``dist-newstyle/build/p-0.1/build/pexe/pexe``. - -- In cabal-install-2.0, the dist directory for a package ``p-0.1`` - defining a library built with GHC 8.0.1 on 64-bit Linux is - ``dist-newstyle/build/x86_64-linux/ghc-8.0.1/p-0.1``. When - per-component builds are enabled (any non-Custom package), a - subcomponent like an executable or test suite named ``pexe`` will be - stored at - ``dist-newstyle/build/x86_64-linux/ghc-8.0.1/p-0.1/c/pexe``; thus, - the full path of the executable is - ``dist-newstyle/build/x86_64-linux/ghc-8.0.1/p-0.1/c/pexe/build/pexe/pexe`` - (you can see why we want this to be an implementation detail!) - -- In cabal-install-2.2 and above, the ``/c/`` part of the above path - is replaced with one of ``/l/``, ``/x/``, ``/f/``, ``/t/``, or - ``/b/``, depending on the type of component (sublibrary, - executable, foreign library, test suite, or benchmark - respectively). So the full path to an executable named ``pexe`` - compiled with GHC 8.0.1 on a 64-bit Linux is now - ``dist-newstyle/build/x86_64-linux/ghc-8.0.1/p-0.1/x/pexe/build/pexe/pexe``; - for a benchmark named ``pbench`` it now is - ``dist-newstyle/build/x86_64-linux/ghc-8.0.1/p-0.1/b/pbench/build/pbench/pbench``; - - -The paths are a bit longer in 2.0 and above but the benefit is that you can -transparently have multiple builds with different versions of GHC. We -plan to add the ability to create aliases for certain build -configurations, and more convenient paths to access particularly useful -build products like executables. +The build products for a project are found under the ``dist-newstyle`` +directory. The actual paths are intended to be an implementation +detail; you can find the true path for e.g. an executable using the +``cabal list-bin`` command. But for the sake of concreteness we describe +Cabal's current policy for build product paths below. + +When per-component builds are enabled (any non-Custom package), a +subcomponent like an executable or test suite named ``pexe`` will be +stored at +``dist-newstyle/build/x86_64-linux/ghc-8.0.1/p-0.1//pexe``; thus, +the full path of the executable is +``dist-newstyle/build/x86_64-linux/ghc-8.0.1/p-0.1//pexe/build/pexe/pexe`` +(you can see why we want this to be an implementation detail!) + +Where ```` is one of ``/l/``, ``/x/``, ``/f/``, ``/t/``, or +``/b/``, depending on the type of component (sublibrary, +executable, foreign library, test suite, or benchmark +respectively). So the full path to an executable named ``pexe`` +compiled with GHC 8.0.1 on a 64-bit Linux is now +``dist-newstyle/build/x86_64-linux/ghc-8.0.1/p-0.1/x/pexe/build/pexe/pexe``; +for a benchmark named ``pbench`` it is +``dist-newstyle/build/x86_64-linux/ghc-8.0.1/p-0.1/b/pbench/build/pbench/pbench`` Caching ------- -Nix-style local builds support a robust caching system which helps to reduce +Cabal supports a robust caching system which helps to reduce the time it takes to execute a rebuild cycle. While the details of how ``cabal-install`` does caching are an implementation detail and may change in the future, knowing what gets cached is helpful for