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

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

#include <build2/bin/target>

#include <build2/cc/types>

#include <build2/cc/module>

using namespace std;
using namespace butl;

namespace build2
{
  namespace cc
  {
    using namespace bin;

    // Extract system library search paths from GCC (gcc/g++) or compatible
    // (Clang, Intel) using the -print-search-dirs option.
    //
    dir_paths config_module::
    gcc_library_search_paths (process_path& xc, scope& rs) const
    {
      dir_paths r;

      cstrings args;
      string std; // Storage.

      args.push_back (xc.recall_string ());
      append_options (args, rs, c_coptions);
      append_options (args, rs, x_coptions);
      if (!tstd.empty ()) args.push_back (tstd.c_str ());
      append_options (args, rs, c_loptions);
      append_options (args, rs, x_loptions);
      args.push_back ("-print-search-dirs");
      args.push_back (nullptr);

      if (verb >= 3)
        print_process (args);

      string l;
      try
      {
        process pr (xc, args.data (), 0, -1); // Open pipe to stdout.

        try
        {
          ifdstream is (pr.in_ofd, fdstream_mode::skip, ifdstream::badbit);

          string s;
          while (getline (is, s))
          {
            if (s.compare (0, 12, "libraries: =") == 0)
            {
              l.assign (s, 12, string::npos);
              break;
            }
          }

          is.close (); // Don't block.

          if (!pr.wait ())
            throw failed ();
        }
        catch (const ifdstream::failure&)
        {
          pr.wait ();
          fail << "error reading " << x_lang << " compiler -print-search-dirs "
               << "output";
        }
      }
      catch (const process_error& e)
      {
        error << "unable to execute " << args[0] << ": " << e.what ();

        if (e.child ())
          exit (1);

        throw failed ();
      }

      if (l.empty ())
        fail << "unable to extract " << x_lang << " compiler system library "
             << "search paths";

      // Now the fun part: figuring out which delimiter is used. Normally it
      // is ':' but on Windows it is ';' (or can be; who knows for sure). Also
      // note that these paths are absolute (or should be). So here is what we
      // are going to do: first look for ';'. If found, then that's the
      // delimiter. If not found, then there are two cases: it is either a
      // single Windows path or the delimiter is ':'. To distinguish these two
      // cases we check if the path starts with a Windows drive.
      //
      char d (';');
      string::size_type e (l.find (d));

      if (e == string::npos &&
          (l.size () < 2 || l[0] == '/' || l[1] != ':'))
      {
        d = ':';
        e = l.find (d);
      }

      // Now chop it up. We already have the position of the first delimiter
      // (if any).
      //
      for (string::size_type b (0);; e = l.find (d, (b = e + 1)))
      {
        r.emplace_back (l, b, (e != string::npos ? e - b : e));
        r.back ().normalize ();

        if (e == string::npos)
          break;
      }

      return r;
    }
  }
}