aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/config/module.hxx
blob: 543c4866c278d19c97a48b55a672ee6bb521fb42 (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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// file      : libbuild2/config/module.hxx -*- C++ -*-
// license   : MIT; see accompanying LICENSE file

#ifndef LIBBUILD2_CONFIG_MODULE_HXX
#define LIBBUILD2_CONFIG_MODULE_HXX

#include <cstring> // strncmp()

#include <libbutl/prefix-map.mxx>

#include <libbuild2/types.hxx>
#include <libbuild2/utility.hxx>

#include <libbuild2/scope.hxx>
#include <libbuild2/module.hxx>
#include <libbuild2/variable.hxx>

#include <libbuild2/config/utility.hxx>

namespace build2
{
  namespace config
  {
    // An ordered list of build system modules each with an ordered list of
    // config.* variables and their "save flags" (see save_variable()) that
    // are used (as opposed to just being specified) in this configuration.
    // Populated by the config utility functions (required(), optional()) and
    // saved in the order populated. If flags are absent, then this variable
    // was marked as "unsaved" (always transient).
    //
    // The optional save function can be used to implement custom variable
    // saving, for example, as a difference appended to the base value. The
    // second half of the result is the assignment operator to use.
    //
    using save_variable_function =
      pair<names_view, const char*> (const value&,
                                     const value* base,
                                     names& storage);
    struct saved_variable
    {
      reference_wrapper<const variable> var;
      optional<uint64_t> flags;
      save_variable_function* save;
    };

    struct saved_variables: vector<saved_variable>
    {
      // Normally each module only have a handful of config variables and we
      // only do this during configuration so for now we do linear search
      // instead of adding a map.
      //
      const_iterator
      find (const variable& var) const
      {
        return find_if (
          begin (),
          end (),
          [&var] (const saved_variable& v) {return var == v.var;});
      }
    };

    struct saved_modules: butl::prefix_map<string, saved_variables, '.'>
    {
      // Priority order with INT32_MIN being the highest. Modules with the
      // same priority are saved in the order inserted.
      //
      multimap<std::int32_t, const_iterator> order;

      pair<iterator, bool>
      insert (string name, int prio = 0)
      {
        auto p (emplace (move (name), saved_variables ()));

        if (p.second)
          order.emplace (prio, p.first);

        return p;
      }
    };

    // List of environment variable names that effect this project.
    //
    // Note that on Windows environment variable names are case-insensitive.
    //
    struct saved_environment: vector<string>
    {
      // Compare environment variable names.
      //
      static inline bool
      compare (const string& x,
               const string& y,
               size_t xn = string::npos,
               size_t yn = string::npos)
      {
        if (xn == string::npos) xn = x.size ();
        if (yn == string::npos) yn = y.size ();

        return xn == yn &&
#ifdef _WIN32
          icasecmp (x.c_str (), y.c_str (), xn) == 0
#else
          strncmp (x.c_str (), y.c_str (), xn) == 0
#endif
          ;
      }

      iterator
      find (const string& v)
      {
        return find_if (
          begin (),
          end (),
          [&v] (const string& v1) {return compare (v, v1);});
      }

      const_iterator
      find (const string& v) const
      {
        return find_if (
          begin (),
          end (),
          [&v] (const string& v1) {return compare (v, v1);});
      }

      void
      insert (string v)
      {
        if (find (v) == end ())
          push_back (move (v));
      }

      void
      erase (const string& v)
      {
        auto i (find (v));
        if (i != end ())
          vector<string>::erase (i);
      }
    };

    class module: public build2::module
    {
    public:
      config::saved_modules saved_modules;

      // Return true if variable/module were newly inserted.
      //
      bool
      save_variable (const variable&,
                     optional<uint64_t> flags,
                     save_variable_function* = nullptr);

      static void
      save_variable (scope&, const variable&, optional<uint64_t>);

      bool
      save_module (const char* name, int prio = 0);

      static void
      save_module (scope&, const char*, int);

      const saved_variable*
      find_variable (const variable& var)
      {
        auto i (saved_modules.find_sup (var.name));
        if (i != saved_modules.end ())
        {
          auto j (i->second.find (var));
          if (j != i->second.end ())
            return &*j;
        }

        return nullptr;
      }

      void
      save_environment (const char* var)
      {
        saved_environment.insert (var);
      }

      static void
      save_environment (scope&, const char*);

      config::saved_environment saved_environment;
      strings old_environment;

      // Configure/disfigure hooks.
      //
      static bool
      configure_post (scope&, configure_post_hook*);

      static bool
      disfigure_pre (scope&, disfigure_pre_hook*);

      small_vector<configure_post_hook*, 1> configure_post_;
      small_vector<disfigure_pre_hook*,  1> disfigure_pre_;

      // Cached (during init) config.config.persist value, if defined.
      //
      const vector<pair<string, string>>* persist = nullptr;

      static const string name;
      static const uint64_t version;
    };

    // Implementation-specific utilities.
    //

    inline path
    config_file (const scope& rs)
    {
      return (rs.out_path () /
              rs.root_extra->build_dir /
              "config." + rs.root_extra->build_ext);
    }
  }
}

#endif // LIBBUILD2_CONFIG_MODULE_HXX