aboutsummaryrefslogtreecommitdiff
path: root/build2/bin/rule.cxx
blob: 9adb6925663f56eabdc35fa7ffb422b74098a2f7 (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
// file      : build2/bin/rule.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#include <build2/bin/rule>

#include <build2/scope>
#include <build2/target>
#include <build2/algorithm>
#include <build2/diagnostics>

#include <build2/bin/target>

using namespace std;

namespace build2
{
  namespace bin
  {
    // obj
    //
    match_result obj_rule::
    match (slock&, action a, target& t, const string&) const
    {
      fail << diag_doing (a, t) << " target group" <<
        info << "explicitly select obje{}, obja{}, or objs{} member";

      return false;
    }

    recipe obj_rule::
    apply (slock&, action, target&) const {return empty_recipe;}

    // lib
    //
    // The whole logic is pretty much as if we had our two group members as
    // our prerequisites.
    //

    struct match_data
    {
      const string& type;
    };

    static_assert (sizeof (match_data) <= target::data_size,
                   "insufficient space");

    match_result lib_rule::
    match (slock& ml, action act, target& xt, const string&) const
    {
      lib& t (xt.as<lib> ());

      // @@ We have to re-query it on each match_only()!

      // Get the library type to build. If not set for a target, this
      // should be configured at the project scope by init().
      //
      const string& type (cast<string> (t["bin.lib"]));

      bool a (type == "static" || type == "both");
      bool s (type == "shared" || type == "both");

      if (!a && !s)
        fail << "unknown library type: " << type <<
          info << "'static', 'shared', or 'both' expected";

      // Search and pre-match the members. The pre-match here is part
      // of the "library meta-information protocol" that could be used
      // by the module that actually builds the members. The idea is
      // that pre-matching members may populate our prerequisite_targets
      // with prerequisite libraries from which others can extract the
      // meta-information about the library, such as the options to use
      // when linking it, etc.
      //
      if (a)
      {
        if (t.a == nullptr)
          t.a = &search<liba> (t.dir, t.out, t.name, nullptr, nullptr);

        match_only (ml, act, *t.a);
      }

      if (s)
      {
        if (t.s == nullptr)
          t.s = &search<libs> (t.dir, t.out, t.name, nullptr, nullptr);

        match_only (ml, act, *t.s);
      }

      t.data (match_data {type}); // Save in the target's auxilary storage.

      match_result mr (true);

      // If there is an outer operation, indicate that we match
      // unconditionally so that we don't override ourselves.
      //
      if (act.outer_operation () != 0)
        mr.recipe_action = action (act.meta_operation (), act.operation ());

      return mr;
    }

    recipe lib_rule::
    apply (slock& ml, action act, target& xt) const
    {
      lib& t (xt.as<lib> ());

      const match_data& md (t.data<match_data> ());
      const string& type (md.type);

      bool a (type == "static" || type == "both");
      bool s (type == "shared" || type == "both");

      // Now we do full match.
      //
      if (a)
        build2::match (ml, act, *t.a);

      if (s)
        build2::match (ml, act, *t.s);

      return &perform;
    }

    target_state lib_rule::
    perform (action act, const target& xt)
    {
      const lib& t (xt.as<lib> ());

      const match_data& md (t.data<match_data> ());
      const string& type (md.type);

      bool a (type == "static" || type == "both");
      bool s (type == "shared" || type == "both");

      target* m1 (a ? t.a : nullptr);
      target* m2 (s ? t.s : nullptr);

      if (current_mode == execution_mode::last)
        swap (m1, m2);

      target_state r (target_state::unchanged);

      if (m1 != nullptr)
        r |= execute (act, *m1);

      if (m2 != nullptr)
        r |= execute (act, *m2);

      return r;
    }
  }
}