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

#include <build/bin/rule>

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

#include <build/bin/target>

using namespace std;

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

      return nullptr;
    }

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

    // lib
    //
    // The whole logic is pretty much as if we had our two group
    // members as our prerequisites.
    //
    match_result lib_rule::
    match (action, target& t, const std::string&) const
    {
      return t;
    }

    recipe lib_rule::
    apply (action a, target& xt, const match_result&) const
    {
      lib& t (static_cast<lib&> (xt));

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

      bool ar (type == "static" || type == "both");
      bool so (type == "shared" || type == "both");

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

      if (ar)
      {
        if (t.a == nullptr)
          t.a = &search<liba> (t.dir, t.name, t.ext, nullptr);

        build::match (a, *t.a);
      }

      if (so)
      {
        if (t.so == nullptr)
          t.so = &search<libso> (t.dir, t.name, t.ext, nullptr);

        build::match (a, *t.so);
      }

      // Search and match prerequisite libraries and add them to the
      // prerequisite targets. While we never execute this list
      // ourselves (see perform() below), this is necessary to make
      // the exported options machinery work for the library chains.
      // See cxx.export.*-related code in cxx/rule.cxx for details.
      //
      for (prerequisite& p: group_prerequisites (t))
      {
        if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libso> ())
        {
          target& pt (search (p));
          build::match (a, pt);
          t.prerequisite_targets.push_back (&pt);
        }
      }

      return &perform;
    }

    target_state lib_rule::
    perform (action a, target& xt)
    {
      lib& t (static_cast<lib&> (xt));

      //@@ Not cool we have to do this again. Looks like we need
      //   some kind of a cache vs resolved pointer, like in
      //   prerequisite vs prerequisite_target.
      //
      //
      const string& type (t["bin.lib"].as<const string&> ());
      bool ar (type == "static" || type == "both");
      bool so (type == "shared" || type == "both");

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

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

      target_state r (target_state::unchanged), ts;

      if (m1 != nullptr)
      {
        ts = execute (a, *m1);
        if (ts == target_state::postponed ||
            (ts == target_state::changed && r == target_state::unchanged))
          r = ts;
      }

      if (m2 != nullptr)
      {
        ts = execute (a, *m2);
        if (ts == target_state::postponed ||
            (ts == target_state::changed && r == target_state::unchanged))
          r = ts;
      }

      return r;
    }
  }
}