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

#include <build2/pkgconfig/init>

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

#include <build2/config/utility>

using namespace std;
using namespace butl;

namespace build2
{
  namespace pkgconfig
  {
    bool
    config_init (scope& rs,
                 scope& bs,
                 const location& l,
                 unique_ptr<module_base>&,
                 bool,
                 bool optional,
                 const variable_map& hints)
    {
      tracer trace ("pkgconfig::config_init");
      l5 ([&]{trace << "for " << bs.out_path ();});

      // We only support root loading (which means there can only be one).
      //
      if (&rs != &bs)
        fail (l) << "pkgconfig.config module must be loaded in project root";

      // Enter variables.
      //
      // config.pkgconfig.target is a hint.
      //
      auto& vp (var_pool.rw (rs));

      const variable& c_x (vp.insert<path> ("config.pkgconfig", true));
      const variable& x_path (vp.insert<process_path> ("pkgconfig.path"));

      const variable& c_x_tgt (
        vp.insert<target_triplet> ("config.pkgconfig.target"));

      // Configure.
      //

      // Adjust module priority (between compilers and binutils).
      //
      config::save_module (rs, "pkgconfig", 325);

      process_path pp;
      bool new_val (false); // Set any new values?

      auto p (config::omitted (rs, c_x));

      if (p.first)
      {
        const path& x (cast<path> (p.first));

        try
        {
          // If this is a user-specified value, then it's non-optional.
          //
          pp = process::path_search (x, true);
          new_val = p.second;
        }
        catch (const process_error& e)
        {
          fail << "unable to execute " << x << ": " << e;
        }
      }

      string d; // Default name (pp.initial may be its shallow copy).

      // If we have a target hint, then next try <triplet>-pkg-config.
      //
      if (pp.empty ())
      {
        if (const auto* t = cast_null<target_triplet> (hints[c_x_tgt]))
        {
          d = t->string ();
          d += "-pkg-config";

          l5 ([&]{trace << "trying " << d;});
          pp = process::try_path_search (d, true);
        }
      }

      // Finallly, try just pkg-config.
      //
      if (pp.empty ())
      {
        d = "pkg-config";

        l5 ([&]{trace << "trying " << d;});
        pp = process::try_path_search (d, true);
      }

      bool conf (!pp.empty ());

      if (!conf && !optional)
        fail (l) << "unable to find pkg-config program";

      // Config report.
      //
      if (verb >= (new_val ? 2 : 3))
      {
        diag_record dr (text);
        dr << "pkgconfig " << project (rs) << '@' << rs.out_path () << '\n';

        if (conf)
          dr << "  pkg-config " << pp;
        else
          dr << "  pkg-config " << "not found, leaving unconfigured";
      }

      if (conf)
        rs.assign (x_path) = move (pp);

      return conf;
    }

    bool
    init (scope& rs,
          scope& bs,
          const location& loc,
          unique_ptr<module_base>&,
          bool,
          bool optional,
          const variable_map& hints)
    {
      tracer trace ("pkgconfig::init");
      l5 ([&]{trace << "for " << bs.out_path ();});

      // Load pkgconfig.config.
      //
      if (!cast_false<bool> (rs["pkgconfig.config.loaded"]))
      {
        if (!load_module (rs, rs, "pkgconfig.config", loc, optional, hints))
          return false;
      }
      else if (!cast_false<bool> (rs["pkgconfig.config.configured"]))
      {
        if (!optional)
          fail << "pkgconfig module could not be configured" <<
            info << "re-run with -V option for more information";

        return false;
      }

      // For now pkgconfig and pkgconfig.config is pretty much the same.
      //

      return true;
    }
  }
}