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

#include <build2/bin/guess>

#include <build2/diagnostics>

using namespace std;

namespace build2
{
  namespace bin
  {
    bin_info
    guess (const path& ar, const path& ranlib)
    {
      tracer trace ("bin::guess");

      bin_info r;
      string& as (r.ar_signature);

      // Binutils, LLVM, and FreeBSD ar/ranlib all recognize the --version
      // option, so start with that.
      //
      {
        auto f = [] (string& l) -> string
        {
          // Binutils ar --version output has a line that starts with
          // "GNU ar ".
          //
          if (l.compare (0, 7, "GNU ar ") == 0)
            return move (l);

          // LLVM ar --version output has a line that starts with
          // "LLVM version ".
          //
          if (l.compare (0, 13, "LLVM version ") == 0)
            return move (l);

          // FreeBSD ar --verison output starts with "BSD ar ".
          //
          if (l.compare (0, 7, "BSD ar ") == 0)
            return move (l);

          return string ();
        };

        // Suppress all the errors because we may be trying an unsupported
        // option.
        //
        sha256 cs;
        as = run<string> (ar, "--version", f, false, false, &cs);

        if (!as.empty ())
          r.ar_checksum = cs.string ();
      }

      // On Mac OS X (and probably also older BSDs) ar/ranlib doesn't have an
      // option to display version or help. If we run it without any arguments
      // it dumps usage and exist with an error status. So we will have to use
      // that.
      //
      if (as.empty ())
      {
        auto f = [] (string& l) -> string
        {
          return l.find (" ar ") == string::npos ? string () : move (l);
        };

        // Redirect STDERR to STDOUT and ignore exit status.
        //
        sha256 cs;
        as = run<string> (ar, f, false, true, &cs);

        if (!as.empty ())
        {
          l4 ([&]{trace << "generic ar signature '" << as << "'";});

          r.ar_signature = "Generic ar";
          r.ar_checksum = cs.string ();
        }
      }

      if (as.empty ())
        fail << "unable to guess " << ar << " signature";

      // Now repeat pretty much the same steps for ranlib if requested.
      //
      if (ranlib.empty ())
        return r;

      string& rs (r.ranlib_signature);

      // Binutils, LLVM, and FreeBSD.
      //
      {
        auto f = [] (string& l) -> string
        {
          // "GNU ranlib ".
          //
          if (l.compare (0, 11, "GNU ranlib ") == 0)
            return move (l);

          // "LLVM version ".
          //
          if (l.compare (0, 13, "LLVM version ") == 0)
            return move (l);

          // "ranlib " (note: not "BSD ranlib " for some reason).
          //
          if (l.compare (0, 7, "ranlib ") == 0)
            return move (l);

          return string ();
        };

        sha256 cs;
        rs = run<string> (ranlib, "--version", f, false, false, &cs);

        if (!rs.empty ())
          r.ranlib_checksum = cs.string ();
      }

      // Mac OS X (and probably also older BSDs).
      //
      if (rs.empty ())
      {
        auto f = [] (string& l) -> string
        {
          return l.find ("ranlib") == string::npos ? string () : move (l);
        };

        // Redirect STDERR to STDOUT and ignore exit status.
        //
        sha256 cs;
        rs = run<string> (ranlib, f, false, true, &cs);

        if (!rs.empty ())
        {
          l4 ([&]{trace << "generic ranlib signature '" << rs << "'";});

          r.ranlib_signature = "Generic ranlib";
          r.ranlib_checksum = cs.string ();
        }
      }

      if (rs.empty ())
        fail << "unable to guess " << ranlib << " signature";

      return r;
    }
  }
}