summaryrefslogtreecommitdiff
path: root/ruby_1_9_3/ext/dbm/extconf.rb
blob: bedd1131f03678f06a7c65bc91a602ef23e25701 (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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
require 'mkmf'

dir_config("dbm")

if dblib = with_config("dbm-type", nil)
  dblib = dblib.split(/[ ,]+/)
else
  dblib = %w(libc db db2 db1 db5 db4 db3 dbm gdbm gdbm_compat qdbm)
end

headers = {
  "libc" => ["ndbm.h"], # 4.4BSD libc contains Berkeley DB 1.
  "db" => ["db.h"],
  "db1" => ["db1/ndbm.h", "db1.h", "ndbm.h"],
  "db2" => ["db2/db.h", "db2.h", "db.h"],
  "db3" => ["db3/db.h", "db3.h", "db.h"],
  "db4" => ["db4/db.h", "db4.h", "db.h"],
  "db5" => ["db5/db.h", "db5.h", "db.h"],
  "dbm" => ["ndbm.h"], # traditional ndbm (4.3BSD)
  "gdbm" => ["gdbm-ndbm.h", "ndbm.h", "gdbm/ndbm.h"], # gdbm until 1.8.0
  "gdbm_compat" => ["gdbm-ndbm.h", "ndbm.h", "gdbm/ndbm.h"], # gdbm since 1.8.1
  "qdbm" => ["relic.h", "qdbm/relic.h"],
}

class << headers
  attr_accessor :found
  attr_accessor :defs
end
headers.found = []
headers.defs = nil

def headers.db_check(db, hdr)
  old_libs = $libs.dup
  old_defs = $defs.dup
  result = db_check2(db, hdr)
  if !result
    $libs = old_libs
    $defs = old_defs
  end
  result
end

# BEGIN BACKPORTED FROM 2.0
class String
  # Wraps a string in escaped quotes if it contains whitespace.
  def quote
    /\s/ =~ self ? "\"#{self}\"" : "#{self}"
  end

  # Generates a string used as cpp macro name.
  def tr_cpp
    strip.upcase.tr_s("^A-Z0-9_*", "_").tr_s("*", "P")
  end

  def funcall_style
    /\)\z/ =~ self ? dup : "#{self}()"
  end

  def sans_arguments
    self[/\A[^()]+/]
  end
end

  def rm_f(*files)
    opt = (Hash === files.last ? [files.pop] : [])
    FileUtils.rm_f(Dir[*files.flatten], *opt)
  end

  def try_func(func, libs, headers = nil, opt = "", &b)
    headers = cpp_include(headers)
    case func
    when /^&/
      decltype = proc {|x|"const volatile void *#{x}"}
    when /\)$/
      call = func
    else
      call = "#{func}()"
      decltype = proc {|x| "void ((*#{x})())"}
    end
    if opt and !opt.empty?
      [[:to_str], [:join, " "], [:to_s]].each do |meth, *args|
        if opt.respond_to?(meth)
          break opt = opt.send(meth, *args)
        end
      end
      opt = "#{opt} #{libs}"
    else
      opt = libs
    end
    decltype && try_link(<<"SRC", opt, &b) or
#{headers}
/*top*/
#{MAIN_DOES_NOTHING}
extern int t(void);
int t(void) { #{decltype["volatile p"]}; p = (#{decltype[]})#{func}; return 0; }
SRC
    call && try_link(<<"SRC", opt, &b)
#{headers}
/*top*/
#{MAIN_DOES_NOTHING}
extern int t(void);
int t(void) { #{call}; return 0; }
SRC
  end

  def try_var(var, headers = nil, opt = "", &b)
    headers = cpp_include(headers)
    try_compile(<<"SRC", opt, &b)
#{headers}
/*top*/
#{MAIN_DOES_NOTHING}
extern int t(void);
int t(void) { const volatile void *volatile p; p = &(&#{var})[0]; return 0; }
SRC
  end

  def have_library(lib, func = nil, headers = nil, opt = "", &b)
    func = "main" if !func or func.empty?
    lib = with_config(lib+'lib', lib)
    checking_for checking_message(func.funcall_style, LIBARG%lib, opt) do
      if COMMON_LIBS.include?(lib)
        true
      else
        libs = append_library($libs, lib)
        if try_func(func, libs, headers, opt, &b)
          $libs = libs
          true
        else
          false
        end
      end
    end
  end

  def have_func(func, headers = nil, opt = "", &b)
    checking_for checking_message(func.funcall_style, headers, opt) do
      if try_func(func, $libs, headers, opt, &b)
        $defs << "-DHAVE_#{func.sans_arguments.tr_cpp}"
        true
      else
        false
      end
    end
  end

  def have_var(var, headers = nil, opt = "", &b)
    checking_for checking_message(var, headers, opt) do
      if try_var(var, headers, opt, &b)
        $defs.push(format("-DHAVE_%s", var.tr_cpp))
        true
      else
        false
      end
    end
  end

  def try_cpp(src, opt="", *opts, &b)
    try_do(src, cpp_command(CPPOUTFILE, opt), *opts, &b)
  ensure
    rm_f "conftest*"
  end

  alias :try_header :try_cpp

  def have_header(header, preheaders = nil, opt = "", &b)
    checking_for header do
      if try_header(cpp_include(preheaders)+cpp_include(header), opt, &b)
        $defs.push(format("-DHAVE_%s", header.tr_cpp))
        true
      else
        false
      end
    end
  end

  def convertible_int(type, headers = nil, opts = nil, &b)
    type, macname = *type
    checking_for("convertible type of #{type}", STRING_OR_FAILED_FORMAT) do
      if UNIVERSAL_INTS.include?(type)
        type
      else
        typedef, member, prelude = typedef_expr(type, headers, &b)
        if member
          prelude << "static rbcv_typedef_ rbcv_var;"
          compat = UNIVERSAL_INTS.find {|t|
            try_static_assert("sizeof(rbcv_var.#{member}) == sizeof(#{t})", [prelude], opts, &b)
          }
        else
          next unless signed = try_signedness(typedef, member, [prelude])
          u = "unsigned " if signed > 0
          prelude << "extern rbcv_typedef_ foo();"
          compat = UNIVERSAL_INTS.find {|t|
            try_compile([prelude, "extern #{u}#{t} foo();"].join("\n"), opts, :werror=>true, &b)
          }
        end
        if compat
          macname ||= type.sub(/_(?=t\z)/, '').tr_cpp
          conv = (compat == "long long" ? "LL" : compat.upcase)
          compat = "#{u}#{compat}"
          typename = type.tr_cpp
          $defs.push(format("-DSIZEOF_%s=SIZEOF_%s", typename, compat.tr_cpp))
          $defs.push(format("-DTYPEOF_%s=%s", typename, compat.quote))
          $defs.push(format("-DPRI_%s_PREFIX=PRI_%s_PREFIX", macname, conv))
          conv = (u ? "U" : "") + conv
          $defs.push(format("-D%s2NUM=%s2NUM", macname, conv))
          $defs.push(format("-DNUM2%s=NUM2%s", macname, conv))
          compat
        end
      end
    end
  end
# END BACKPORTED FROM 2.0

def have_libvar(var, headers = nil, opt = "", &b)
  checking_for checking_message([*var].compact.join(' '), headers, opt) do
    try_libvar(var, headers, opt, &b)
  end
end

def try_libvar(var, headers = nil, opt = "", &b)
  var, type = *var
  if try_link(<<"SRC", opt, &b)
#{cpp_include(headers)}
/*top*/
int main(int argc, char *argv[]) {
  typedef #{type || 'int'} conftest_type;
  extern conftest_type #{var};
  conftest_type *conftest_var = &#{var};
  return 0;
}
SRC
    $defs.push(format("-DHAVE_LIBVAR_%s", var.tr_cpp))
    true
  else
    false
  end
end


def headers.db_check2(db, hdr)
  hsearch = nil

  case db
  when /^db[2-5]?$/
    hsearch = "-DDB_DBM_HSEARCH"
  when "gdbm_compat"
    have_library("gdbm") or return false
  end

  if have_type("DBM", hdr, hsearch) and
     (db == 'libc' ? have_func('dbm_open("", 0, 0)', hdr, hsearch) :
                     have_library(db, 'dbm_open("", 0, 0)', hdr, hsearch)) and
     have_func('dbm_clearerr((DBM *)0)', hdr, hsearch) and
     (/\Adb\d?\z/ =~ db || db == 'libc' || !have_macro('_DB_H_', hdr, hsearch)) # _DB_H_ should not be defined except Berkeley DB.
    case db
    when /\Adb\d?\z/
      have_func('db_version((int *)0, (int *)0, (int *)0)', hdr, hsearch)
    when /\Agdbm/
      have_var("gdbm_version", hdr, hsearch)
      # gdbm_version is not declared by ndbm.h until gdbm 1.8.3.
      # We can't include ndbm.h and gdbm.h because they both define datum type.
      # ndbm.h includes gdbm.h and gdbm_version is declared since gdbm 1.9.
      have_libvar(["gdbm_version", "char *"], hdr, hsearch)
    when /\Aqdbm\z/
      have_var("dpversion", hdr, hsearch)
    end
    if hsearch
      $defs << hsearch
      @defs = hsearch
    end
    $defs << '-DDBM_HDR="<'+hdr+'>"'
    @found << hdr
    true
  else
    false
  end
end

if dblib.any? {|db| headers.fetch(db, ["ndbm.h"]).any? {|hdr| headers.db_check(db, hdr) } }
  have_header("cdefs.h")
  have_header("sys/cdefs.h")
  have_func("dbm_pagfno((DBM *)0)", headers.found, headers.defs)
  have_func("dbm_dirfno((DBM *)0)", headers.found, headers.defs)
  convertible_int("datum.dsize", headers.found, headers.defs)
  create_makefile("dbm")
end