aboutsummaryrefslogtreecommitdiff
path: root/build/module.cxx
blob: 79a9bdb858ecb164828b9807c2d5703db2f4c706 (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
// file      : build/module.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#include <build/module>

#include <utility> // make_pair()

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

using namespace std;

namespace build
{
  available_module_map builtin_modules;

  void
  boot_module (const string& name, scope& rs, const location& loc)
  {
    // First see if this modules has already been loaded for this project.
    //
    loaded_module_map& lm (rs.modules);
    auto i (lm.find (name));

    if (i != lm.end ())
    {
      module_state& s (i->second);

      // The only valid situation here is if the module has already been
      // bootstrapped.
      //
      assert (s.boot);
      return;
    }

    // Otherwise search for this module.
    //
    auto j (builtin_modules.find (name));

    if (j == builtin_modules.end ())
      fail (loc) << "unknown module " << name;

    const module_functions& mf (j->second);

    if (mf.boot == nullptr)
      fail (loc) << "module " << name << " shouldn't be loaded in bootstrap";

    i = lm.emplace (name, module_state {true, mf.init, nullptr, loc}).first;
    mf.boot (rs, loc, i->second.module);
  }

  bool
  load_module (bool opt,
               const string& name,
               scope& rs,
               scope& bs,
               const location& loc)
  {
    // First see if this modules has already been loaded for this project.
    //
    loaded_module_map& lm (rs.modules);
    auto i (lm.find (name));
    bool f (i == lm.end ());

    if (f)
    {
      // Otherwise search for this module.
      //
      auto j (builtin_modules.find (name));

      if (j == builtin_modules.end ())
      {
        if (!opt)
          fail (loc) << "unknown module " << name;
      }
      else
      {
        const module_functions& mf (j->second);

        if (mf.boot != nullptr)
          fail (loc) << "module " << name << " should be loaded in bootstrap";

        i = lm.emplace (
          name, module_state {false, mf.init, nullptr, loc}).first;
      }
    }
    else
    {
      module_state& s (i->second);

      if (s.boot)
      {
        s.boot = false;
        f = true; // This is a first call to init.
      }
    }

    bool l (i != lm.end ());
    bool c (l && i->second.init (rs, bs, loc, i->second.module, f, opt));

    const variable& lv (var_pool.find (name + ".loaded",
                                       variable_visibility::project,
                                       bool_type));
    const variable& cv (var_pool.find (name + ".configured",
                                       variable_visibility::project,
                                       bool_type));
    bs.assign (lv) = l;
    bs.assign (cv) = c;

    return l && c;
  }
}