2 # Copyright (c) 2005, 2006 Tilman Sauerbeck (tilman at code-monkey de)
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
12 # The above copyright notice and this permission notice shall be
13 # included in all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 require "rake/tasklib"
30 class ConfigureTask < TaskLib
31 CACHE_FILE = ".configure_state.yaml"
35 def initialize # :yield: self
36 @tests = TestList.new(load_tests || [])
38 yield self if block_given?
43 # returns the test with the specified name
45 @tests.find { |t| t.name == name }
54 r = YAML.load(File.read(CACHE_FILE)) rescue nil
56 r.is_a?(TestList) ? r : nil
60 desc "Remove configure results"
61 task :clobber_configure do
62 FileUtils::Verbose.rm_f(CACHE_FILE)
65 task :clobber => :clobber_configure
67 desc "Configure this package"
68 task :configure => [CACHE_FILE]
72 t.on_checking.reverse_each { |b| b.call }
75 t.on_success.reverse_each { |b| b.call }
77 t.on_failure.reverse_each { |b| b.call }
81 # store the test results in CACHE_FILE
82 File.open(CACHE_FILE, "w") { |f| YAML.dump(@tests, f) }
86 class TestList < Array
87 def initialize(stored_tests)
88 @stored_tests = stored_tests
97 args.each { |a| assign_result(a) }
107 def assign_result(test)
108 st = @stored_tests.find { |st| st.name == test.name }
109 test.result = st.result unless st.nil?
114 attr_reader :name, :on_checking, :on_success, :on_failure
115 attr_accessor :result
117 def initialize(name, opts = {}) # :yield: self
126 if opts[:is_critical]
127 @on_failure << lambda { raise }
130 yield self if block_given?
133 def to_yaml_properties
141 def can_exec_binary?(bin)
143 tf = Tempfile.open("configuretask")
149 rescue SystemCallError
158 $?.exitstatus != 0xb00bface
162 class FooConfigTest < Test
163 def initialize(name, opts = {})
167 @command = "#{name}-config"
169 @on_checking << lambda do
170 print "checking for #{name}... "
174 @on_success << lambda { puts "yes (#{version})" }
175 @on_failure << lambda { puts "no" }
178 def method_missing(m)
183 return false unless can_exec_command?
185 [:version, :cflags, :libs].each do |f|
186 @result[f] = lookup_flags(f)
194 tmp = `#{@command} --#{f}`.strip
195 $?.exitstatus.zero? ? tmp : nil
199 def can_exec_command?
200 can_exec_binary?(@command)
204 class PkgConfigTest < FooConfigTest
205 def initialize(name, opts = {})
208 @command = "pkg-config --silence-errors"
213 f = :modversion if f == :version
215 tmp = `#{@command} --#{f} #{@name}`.strip.tr("\n", "/")
216 $?.exitstatus.zero? ? tmp : nil
220 class CompileTest < Test
221 TMP_FILE = ".compile_test"
223 def CompileTest.cflags
227 def CompileTest.cflags=(f)
231 def initialize(name, code, opts = {})
240 cc = ENV["CC"] || "cc"
241 flags = (ENV["CFLAGS"] || "").dup
242 flags << " -I" + Config::CONFIG["archdir"]
244 unless @opts[:try_link]
248 File.open(TMP_FILE + ".c", "w") do |f|
252 `#{cc} #{flags} #{TMP_FILE}.c -o #{TMP_FILE}.o > /dev/null 2>&1`
253 @result = $?.exitstatus.zero?
255 FileUtils.rm_f("#{TMP_FILE}.c")
256 FileUtils.rm_f("#{TMP_FILE}.o")
260 class HaveFuncTest < CompileTest
261 def initialize(name, includes = [], opts = {})
262 super(name, assemble_code(name, includes), opts)
264 @on_checking << lambda do
265 print "checking for #{name}... "
269 @on_success << lambda { puts "yes" }
270 @on_failure << lambda { puts "no" }
274 def assemble_code(func, includes)
275 header = includes.inject("") do |a, h|
276 a << "#include <#{h}>\n"
281 void *foo = (void *) #{func};