aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/install/functions.cxx
blob: 9f5fa44aa74fd3aa1922a6db5d392a3cf4ffa35d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// file      : libbuild2/install/functions.cxx -*- C++ -*-
// license   : MIT; see accompanying LICENSE file

#include <libbuild2/function.hxx>
#include <libbuild2/variable.hxx>

#include <libbuild2/install/utility.hxx>

namespace build2
{
  namespace install
  {
    void
    functions (function_map& m)
    {
      function_family f (m, "install");

      // $install.resolve(<dir>[, <rel_base>])
      //
      // Resolve potentially relative install.* value to an absolute and
      // normalized directory based on (other) install.* values visible from
      // the calling scope.
      //
      // If rel_base is specified and is not empty, then make the resulting
      // directory relative to it. If rel_base itself is relative, first
      // resolve it to an absolute and normalized directory based on install.*
      // values. Note that this argument is mandatory if this function is
      // called during relocatable installation (install.relocatable is true).
      // While you can pass empty directory to suppress this functionality,
      // make sure this does not render the result non-relocatable.
      //
      // As an example, consider an executable that supports loading plugins
      // and requires the plugin installation directory to be embedded into
      // the executable during the build. The common way to support
      // relocatable installations for such cases is to embed a path relative
      // to the executable and complete it at runtime. If you would like to
      // always use the relative path, regardless of whether the installation
      // is relocatable of not, then you can simply always pass rel_base, for
      // example:
      //
      // plugin_dir = $install.resolve($install.lib, $install.bin)
      //
      // Alternatively, if you would like to continue using absolute paths for
      // non-relocatable installations, then you can use something like this:
      //
      // plugin_dir = $install.resolve($install.lib, ($install.relocatable ? $install.bin : [dir_path] ))
      //
      // Finally, if you are unable to support relocatable installations, the
      // correct way to handle this is NOT to always pass an empty path for
      // rel_base but rather assert in root.build that your project does not
      // support relocatable installations, for example:
      //
      // assert (!$install.relocatable) 'relocatable installation not supported'
      //
      // Note that this function is not pure.
      //
      f.insert (".resolve", false) += [] (const scope* s,
                                          dir_path dir,
                                          optional<dir_path> rel_base)
      {
        if (s == nullptr)
          fail << "install.resolve() called out of scope" << endf;

        if (!rel_base)
        {
          const scope& rs (*s->root_scope ());

          if (cast_false<bool> (rs["install.relocatable"]))
          {
            fail << "relocatable installation requires relative base "
                 << "directory" <<
              info << "pass empty relative base directory if this call does "
                 << "not affect installation relocatability" <<
              info << "or add `assert (!$install.relocatable) 'relocatable "
                 << "installation not supported'` before the call";
          }
        }

        return resolve_dir (*s,
                            move (dir),
                            rel_base ? move (*rel_base) : dir_path ());
      };
    }
  }
}