X-Git-Url: http://git.code-monkey.de/?p=ruby-ecore.git;a=blobdiff_plain;f=rake%2Fconfiguretask.rb;fp=rake%2Fconfiguretask.rb;h=b673c84a8b45fa770a75b23fc999443a76b1d24a;hp=0000000000000000000000000000000000000000;hb=087974f38a80e4052d828562c01cdb44eacd3bf5;hpb=35069ec1047caf040c2adc1d39c464cbb6df3ed0 diff --git a/rake/configuretask.rb b/rake/configuretask.rb new file mode 100644 index 0000000..b673c84 --- /dev/null +++ b/rake/configuretask.rb @@ -0,0 +1,296 @@ +# +# Copyright (c) 2005, 2006 Tilman Sauerbeck (tilman at code-monkey de) +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +require "rake/tasklib" +require "rake/clean" +require "yaml" +require "fileutils" + +module Rake + class ConfigureTask < TaskLib + CACHE_FILE = ".configure_state.yaml" + + attr_reader :tests + + def initialize # :yield: self + @tests = TestList.new(load_tests || []) + + yield self if block_given? + + define + end + + # returns the test with the specified name + def [](name) + @tests.find { |t| t.name == name } + end + + def method_missing(m) + self[m.to_s] + end + + private + def load_tests + r = YAML.load(File.read(CACHE_FILE)) rescue nil + + r.is_a?(TestList) ? r : nil + end + + def define + desc "Remove configure results" + task :clobber_configure do + FileUtils::Verbose.rm_f(CACHE_FILE) + end + + task :clobber => :clobber_configure + + desc "Configure this package" + task :configure => [CACHE_FILE] + + file CACHE_FILE do + @tests.each do |t| + t.on_checking.reverse_each { |b| b.call } + + if t.invoke + t.on_success.reverse_each { |b| b.call } + else + t.on_failure.reverse_each { |b| b.call } + end + end + + # store the test results in CACHE_FILE + File.open(CACHE_FILE, "w") { |f| YAML.dump(@tests, f) } + end + end + + class TestList < Array + def initialize(stored_tests) + @stored_tests = stored_tests + end + + def <<(arg) + assign_result(arg) + super + end + + def push(*args) + args.each { |a| assign_result(a) } + super + end + + def unshift(arg) + assign_result(arg) + super + end + + private + def assign_result(test) + st = @stored_tests.find { |st| st.name == test.name } + test.result = st.result unless st.nil? + end + end + + class Test + attr_reader :name, :on_checking, :on_success, :on_failure + attr_accessor :result + + def initialize(name, opts = {}) # :yield: self + @name = name + @opts = opts + + @result = nil + @on_checking = [] + @on_success = [] + @on_failure = [] + + if opts[:is_critical] + @on_failure << lambda { raise } + end + + yield self if block_given? + end + + def to_yaml_properties + ["@name", "@result"] + end + + def invoke + end + + protected + def can_exec_binary?(bin) + fork do + STDOUT.reopen("/dev/null") + STDERR.reopen("/dev/null") + + begin + exec(bin) + rescue SystemCallError + exit 255 + end + end + + Process.wait + + $?.exitstatus != 255 + end + end + + class FooConfigTest < Test + def initialize(name, opts = {}) + super + + @result = {} + @command = "#{name}-config" + + @on_checking << lambda do + print "checking for #{name}... " + STDOUT.flush + end + + @on_success << lambda { puts "yes (#{version})" } + @on_failure << lambda { puts "no" } + end + + def method_missing(m) + @result[m] + end + + def invoke + return false unless can_exec_command? + + begin + [:version, :cflags, :libs].each do |f| + @result[f] = lookup_flags(f) + end + rescue Exception + @result.clear + end + + !@result.empty? + end + + protected + def lookup_flags(f) + tmp = `#{@command} --#{f}`.strip + + raise unless $?.exitstatus.zero? + tmp + end + + private + def can_exec_command? + can_exec_binary?(@command) + end + end + + class PkgConfigTest < FooConfigTest + def initialize(name, opts = {}) + super + + @command = "pkg-config" + end + + protected + def lookup_flags(f) + f = :modversion if f == :version + + tmp = `#{@command} --silence-errors --#{f} #{@name}`. + strip.tr("\n", "/") + + raise unless $?.exitstatus.zero? + tmp + end + end + + class CompileTest < Test + TMP_FILE = ".compile_test" + + def CompileTest.cflags + @@cflags + end + + def CompileTest.cflags=(f) + @@cflags = f + end + + def initialize(name, code, opts = {}) + super(name, opts) + + @code = code + end + + def invoke + @result = false + + cc = ENV["CC"] || "cc" + flags = (ENV["CFLAGS"] || "").dup + flags << " -I" + Config::CONFIG["archdir"] + + unless @opts[:try_link] + flags << " -c" + end + + File.open(TMP_FILE + ".c", "w") do |f| + f << @code << "\n" + end + + `#{cc} #{flags} #{TMP_FILE}.c -o #{TMP_FILE}.o > /dev/null 2>&1` + @result = $?.exitstatus.zero? + ensure + FileUtils.rm_f("#{TMP_FILE}.c") + FileUtils.rm_f("#{TMP_FILE}.o") + end + end + + class HaveFuncTest < CompileTest + def initialize(name, includes = [], opts = {}) + super(name, assemble_code(name, includes), opts) + + @on_checking << lambda do + print "checking for #{name}... " + STDOUT.flush + end + + @on_success << lambda { puts "yes" } + @on_failure << lambda { puts "no" } + end + + private + def assemble_code(func, includes) + header = includes.inject("") do |a, h| + a << "#include <#{h}>\n" + end + + body =<