aboutsummaryrefslogtreecommitdiff
path: root/build/context.cxx
blob: a0952ec16f9d16790edcb9c5afba438833eb3cad (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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// file      : build/context.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC
// license   : MIT; see accompanying LICENSE file

#include <build/context>

#include <ostream>
#include <cassert>
#include <system_error>

#include <build/scope>
#include <build/diagnostics>

using namespace std;

namespace build
{
  path work;
  path home;

  execution_mode current_mode;
  const target_rule_map* current_rules;

  void
  reset ()
  {
    targets.clear ();
    scopes.clear ();
    variable_pool.clear ();

    // Create global scope. For Win32 we use the empty path since there
    // is no "real" root path. On POSIX, however, this is a real path.
    // See the comment in <build/path-map> for details.
    //
#ifdef _WIN32
    global_scope = &scopes[path ()];
#else
    global_scope = &scopes[path ("/")];
#endif

    global_scope->variables["work"] = work;
    global_scope->variables["home"] = home;
  }

  fs_status<mkdir_status>
  mkdir (const path& d)
  {
    // We don't want to print the command if the directory already
    // exists. This makes the below code a bit ugly.
    //
    mkdir_status ms;

    try
    {
      ms = try_mkdir (d);
    }
    catch (const system_error& e)
    {
      if (verb >= 1)
        text << "mkdir " << d.string ();
      else
        text << "mkdir " << d;

      fail << "unable to create directory " << d.string () << ": "
           << e.what ();
    }

    if (ms == mkdir_status::success)
    {
      if (verb >= 1)
        text << "mkdir " << d.string ();
      else
        text << "mkdir " << d;
    }

    return ms;
  }

  path
  src_out (const path& out, scope& s)
  {
    return src_out (out,
                    s["out_root"].as<const path&> (),
                    s["src_root"].as<const path&> ());
  }

  path
  out_src (const path& src, scope& s)
  {
    return out_src (src,
                    s["out_root"].as<const path&> (),
                    s["src_root"].as<const path&> ());
  }

  path
  src_out (const path& o, const path& out_root, const path& src_root)
  {
    assert (o.sub (out_root));
    return src_root / o.leaf (out_root);
  }

  path
  out_src (const path& s, const path& out_root, const path& src_root)
  {
    assert (s.sub (src_root));
    return out_root / s.leaf (src_root);
  }

  const path* relative_base = &work;

  path
  relative (const path& p)
  {
    const path& b (*relative_base);

    if (b.empty ())
      return p;

    if (p.sub (b))
      return p.leaf (b);

    // If base is a sub-path of {src,out}_root and this path is also a
    // sub-path of it, then use '..' to form a relative path.
    //
    // Don't think this is a good heuristic. For example, why shouldn't
    // we display paths from imported projects as relative if they are
    // more readable than absolute?
    //
    /*
    if ((work.sub (src_root) && p.sub (src_root)) ||
        (work.sub (out_root) && p.sub (out_root)))
      return p.relative (work);
    */

    if (p.root_directory () == b.root_directory ())
    {
      path r (p.relative (b));

      if (r.string ().size () < p.string ().size ())
        return r;
    }

    return p;
  }
}