#!/usr/bin/env ruby # $Id$ =begin GridFlow Copyright (c) 2001,2002 by Mathieu Bouchard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See file ./COPYING for further informations on licensing terms. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =end #----------------------------------------------------------------# require "rbconfig" require "mkmf" require "ftools" include Config def make_expand(x) y=x.gsub(/\$\(([^\)]*)\)/) {CONFIG[$1]} if x!=y then make_expand y else y end end def read_ld_so_conf return [] unless File.exist?("/etc/ld.so.conf") x = File.open("/etc/ld.so.conf"){|f| f.read }.split("\s") x.delete_if { x.length==0 } x end $C_INCLUDE_PATH = ( (ENV["CPLUS_INCLUDE_PATH"]||"").split(":") + (ENV["C_INCLUDE_PATH"]||"").split(":") + ["/usr/include"]).uniq $LIBRARY_PATH = ( (ENV["LIBRARY_PATH"]||"").split(":") + ["/usr/lib","/lib"]).uniq $LD_LIBRARY_PATH = ( (ENV["LD_LIBRARY_PATH"]||"").split(":") + read_ld_so_conf + ["/usr/lib","/lib"]).uniq #for var in [:$C_INCLUDE_PATH, :$LIBRARY_PATH, :$LD_LIBRARY_PATH] do # puts "#{var}: #{eval(var.to_s).inspect}" #end $CFLAGS += " -xc++ -fno-operator-names -falign-functions=4" ruby16a = "#{CONFIG['libdir']}/ruby/#{CONFIG['MAJOR']}.#{CONFIG['MINOR']}/"\ "#{CONFIG['arch']}/#{CONFIG['LIBRUBY_A']}" ruby18a = "#{CONFIG['libdir']}/#{CONFIG['LIBRUBY_A']}" for x in [ruby16a,ruby18a] do $LIBRUBY_A = make_expand x break if File.exist? $LIBRUBY_A end FILES = [ [:directory, "base/", [:ruby, "main.rb"], [:ruby, "flow_objects.rb"], [:ruby, "test.rb"], [:ruby, "source_filter.rb"], [:ruby, "MainLoop.rb"], ], [:directory, "bridge/", [:ruby, "puredata.rb"], ], [:directory, "format/", [:ruby, "main.rb"], ], [:directory, "extra/", [:ruby, "eval_server.rb"], [:ruby, "smpte.rb"], [:ruby, "server_2.rb"], [:ruby, "server_1_grid.rb"], [:ruby, "server_1_ppm.rb"], [:ruby, "jmax_format.rb"], [:ruby, "puredata_format.rb"], ], ] #--------------------------------# $conf={ :LDSOFLAGS => ["-lm"], :BRIDGE_LDFLAGS => ["-lm"], :FEATURES => {}, :FORMATS => [], :OPTIONS => [], :DEFINES => { :JMAX_ARCH => "i686-linux", :RUBY_PREFIX => CONFIG['sitedir'], :PREFIX => "/usr/local", }, :CC => "g++", :OBJS => [], } #----------------------------------------------------------------# # Generic Parts class Or attr_reader :a class< "1.7" log << "error \##{ret}\n" if ret>0 return ret<=0 end def c_test code, *link log = "" log << code << "\n" File.open("/tmp/#{$$}.cpp","w") {|f| f.puts code } command = ["/usr/bin/env", $conf[:CC]] command.concat $CFLAGS.split(/ /).reject{|x| x.length==0 } command.concat ["/tmp/#{$$}.cpp", "-o", "/tmp/#{$$}", *link] launch2 log,*command or return false command = ["/tmp/#{$$}"] launch2 log,*command or return false true ensure LOG.puts log end def asm_test code, *link log = "" log << code << "\n" File.open("/tmp/#{$$}.asm","w") {|f| f.puts code } command = ["/usr/bin/env", "nasm", "/tmp/#{$$}.asm", "-f", "elf", "-o", "/tmp/#{$$}.o"] launch2 log,*command or return false command = ["#{$conf[:CC]}","-o","/tmp/#{$$}","/tmp/#{$$}.o",*link] launch2 log,*command or return false command = ["/tmp/#{$$}"] launch2 log,*command or return false true ensure LOG.puts log end def launch stdin,stdout,stderr,*command # -> returncode child = fork if not child then STDIN.reopen stdin if stdin STDOUT.reopen stdout if stdout STDERR.reopen stderr if stderr exec *command STDERR.puts "SHOULD NOT GET THERE" exit! end child end def join_pid pid Process.waitpid2(pid)[1] end #----------------------------------------------------------------# # Specific to the GridFlow project module Future; end class Feature def initialize(&b) instance_eval(&b) end def self.attr2(sym,&b) eval "def #{sym}(*args,&b) raise args.inspect if args.length>1 if b then @#{sym}=b.extend Future elsif args.length>0 then @#{sym}=args[0] else if Future===@#{sym} then @#{sym}.call else @#{sym} end end end" end attr2 :tag attr2 :name attr2 :status #!@#$ attr2 :uses_so #!@#$ attr2 :uses_bridge_so #!@#$ attr2 :uses_o #!@#$ attr2 :uses_h #!@#$ attr2 :uses_feature #!@#$ attr2 :test #!@#$ attr2 :formats #!@#$ attr2 :options #!@#$ attr2 :unless_feature #!@#$ attr2 :action #!@#$ attr2 :defines #!@#$ end $features = [ Feature.new { tag :libruby name "Ruby as a dynamic library" uses_bridge_so ["-lruby"] test proc { c_test " #include int main () { return rb_rescue==0; } ", "-lruby" } }, Feature.new { tag :librubystatic unless_feature [:libruby] name "Ruby as a static library" uses_bridge_so ["-Wl,--whole-archive"+ " #{$LIBRUBY_A} #{CONFIG['LIBS']} "+ "-Wl,--no-whole-archive"] test proc { c_test " #include int main () { return rb_rescue==0; } ", "-xnone", $LIBRUBY_A, *(CONFIG['LIBS'].split) } options ["HAVE_STATIC_RUBY"] }, Feature.new { tag :fast name "Compile for speed (and not debuggability)" }, Feature.new { tag :pentium name "Pentium-compatible CPU" # todo: -mcpu=pentiumpro, and so on. action proc { $CFLAGS += " -mcpu=pentium" } test proc { (CONFIG["arch"] =~ /i\d86/) and c_test ' #include char get_cpuid[]={ 96,49,192,15,162,139,124,36,36,137,31, 137,87,4,137,79,8,137,71,12,97,195}; main() { char result[16]; int code; ((void(*)(char*))get_cpuid)(result); code = ((int*)result)[3]; result[12]=0; fprintf(stderr,"cpuid: name=\"%12s\", flags=0x%08x\n", result,code); return 0;}' } options ["HAVE_PENTIUM"] }, Feature.new { tag :mmx uses_feature [:pentium] # status :disabled uses_o ["cpu/mmx.o","cpu/mmx_loader.o"] name "MMX-compatible CPU" test proc { asm_test ' global main extern exit align 16 SECTION .data foo: dd 42,0 SECTION .text main: lea esi,[foo] movq mm0,qword[esi] paddd mm0,qword[esi] movq qword [esi],mm0 emms cmp dword [foo], 84 je yes push long 1 call exit yes: push long 0 call exit ', '-lc' } options ["HAVE_MMX"] }, Feature.new { tag :profiler name "profiler (speed measurements)" uses_feature [:pentium] options ["HAVE_TSC_PROFILING"] }, Feature.new { tag :x11 name "X11 Display Protocol" uses_so ["-L/usr/X11R6/lib","-lX11","-lXext"] test proc { c_test " #include int main () {return XSetErrorHandler==0;} ", *uses_so } formats ["X11"] }, Feature.new { tag :x11_shm name "X11 acceleration through shared memory" uses_feature [:x11] uses_so ["-L/usr/X11R6/lib","-lX11","-lXext"] test proc { c_test " #include #include #include #include #include #include int main () {return XShmPutImage==0;} ", *uses_so } options ["HAVE_X11_SHARED_MEMORY"] }, Feature.new { tag :sdl name "Simple Directmedia Layer" uses_so ["-lSDL","-lpthread"] #uses_h ["SDL/SDL.h"] test proc { c_test " #include int main () {return SDL_MapRGB==0;} ", *uses_so } formats ["SDL"] }, Feature.new { tag :aalib name "Ascii Art Library" uses_so ["-laa"] uses_h ["aalib.h"] # status :disabled test proc { c_test " #define aa_hardwareparams aa_hardware_params extern \"C\" { #include }; int main () {return aa_init==0;} ", *uses_so } formats ["AALib"] }, Feature.new { tag :jpeg name "JPEG Library" uses_so ["-ljpeg"] uses_h ["jpeglib.h"] test proc { c_test " extern \"C\" { #include #include }; int main () { return jpeg_write_scanlines==0;} ", *uses_so } formats ["JPEG"] }, Feature.new { tag :videodev name "Video4linux Digitizer Driver Interface" test proc { c_test " #include #include int main () { struct video_window foo; return 0; } " } formats ["VideoDev"] }, Feature.new { tag :mpeg3 name "HeroineWarrior's LibMPEG3" uses_so ["-lmpeg3","-lpthread","-lm", "-L/usr/X11R6/lib","-I/usr/X11R6/include"] uses_h Or["libmpeg3/libmpeg3.h","libmpeg3.h"] test proc {|f| c_test " #include <#{f.uses_h}> int main () { return mpeg3_open==0; } ", *uses_so } formats ["MPEG3"] }, Feature.new { tag :mpeg name "Greg Ward's LibMPEG" unless_feature :mpeg3 uses_so ["-lmpeg"] test proc { c_test " #include int main () { return GetMPEGFrame==0; } ", *uses_so } formats ["MPEG"] }, Feature.new { tag :quicktime name "HeroineWarrior's QuickTime file reader" uses_so Or[ ["-lquicktime","-lpthread","-lpng","-ldl","-lglib"], ["-lquicktime","-lpthread","-lpng","-ldl","-lglib-1.2"]] test proc {|f| c_test %` #include #include int main () { fprintf(stderr,"LQT_VERSION = %s\\n", #ifdef LQT_VERSION LQT_VERSION #else "(undefined)" #endif ); return quicktime_open==0; } `, *f.uses_so } formats ["QuickTime"] }, Feature.new { tag :jmax25 name "IRCAM's jMax 2.5" uses_feature [Or[:libruby,:librubystatic]] defines :JMAXDISTDIR => proc { Dir.getwd + "/bundled/jmax" } test proc { c_test ' #define new new_ #define template template_ #define this this_ #define operator operator_ #define class class_ #include int main () { return 0; } ', "-DLINUXPC" and #!@#$ nonportable $C_INCLUDE_PATH.find {|dir| File.exist?(dir+"/fts/lang/mess.h") } } options ["HAVE_JMAX_2_5"] }, Feature.new { tag :jmax4 # status :disabled name "IRCAM's jMax 4" uses_feature [Or[:libruby,:librubystatic]] unless_feature :jmax25 defines :JMAX4_INSTALL_DIR => proc { `jmax-config --package-dir`.chomp } test proc { c_test ' #define new new_ #define template template_ #define this this_ #define operator operator_ #define class class_ #include int main () { return 0; } ', "-DLINUXPC" and #!@#$ nonportable $C_INCLUDE_PATH.find {|dir| #STDERR.puts dir File.exist?(dir+"/fts/client/version.h") } } options ["HAVE_JMAX_4"] }, Feature.new { tag :puredata name "Miller Puckette's Pure Data" uses_feature [Or[:libruby,:librubystatic]] options ["HAVE_PUREDATA"] defines { path = $C_INCLUDE_PATH.find {|x| File.exist?(x+"/m_pd.h")} {:PUREDATA_PATH => File.dirname(path)+"/lib/pd" }} test proc { c_test " \#include int main () { return 0; } " and $C_INCLUDE_PATH.find {|x| File.exist? x+"/m_pd.h" } } }] $features_h = {} $features.each {|f| $features_h[f.tag]=f } #--------------------------------# def usage log = "" log << "usage: ./configure " log << "[--use-compiler compiler] " log << "[--jmax-dist-dir directory] [--jmax-arch arch] " log << "[--debug] [--debug-harder] [--ruby-prefix directory] " log << "[--prefix directory]" $features_h.keys.map {|k| k.to_s }.sort.each {|k| log << "[--no-#{k}] " } $features_h.keys.map {|k| k.to_s }.sort.each {|k| log << "[--force-#{k}] " } puts while log.length>0 do puts log.slice!(/^.{1,70} /) end end puts if not File.exist?("./configure") puts "Run me from the right directory please." exit 1 end while ARGV.length>0 do arg=ARGV.shift case arg when /=/ ARGV[0,0]=arg.split(/=/) when /^--no-/ name = arg[5..-1].intern puts "there is no feature called #{name}" if not $features_h[name] puts "--no: won't check for feature #{name}" $features_h.delete name when /^--force-/ name = arg[8..-1].intern puts "there is no feature called #{name}" if not $features_h[name] puts "--force: assuming #{name} is there" $features_h[name].test nil when "--static" #!@#$ not working. raise "boo" $conf[:STATIC]=true $CFLAGS += " -static" # ARGV.unshift "--no-libruby" when "--debug" puts "Debug Mode (more error checking; less speed)" $conf[:OPTIONS].push :HAVE_DEBUG when "--debug-harder" puts "Debug Harder Mode (even more error checking; even less speed)" $conf[:OPTIONS].push :HAVE_DEBUG $conf[:OPTIONS].push :HAVE_DEBUG_HARDER when "--jmax-arch"; $conf[:DEFINES][:JMAX_ARCH]=ARGV.shift when "--help"; usage; exit 0 when "--prefix", "--ruby-prefix" $conf[:DEFINES][:RUBY_PREFIX]=ARGV.shift+"/lib/ruby/site_ruby" when "--use-compiler" $conf[:CC] = ARGV.shift else puts "unknown option \"#{arg}\""; usage; exit 1 end end # the ||= lines are patches for old versions of ruby. CONFIG["ruby_version"] ||= "$(MAJOR).$(MINOR)" CONFIG["rubylibdir"] ||= "$(libdir)/ruby/$(ruby_version)" CONFIG["archdir"] ||= CONFIG["rubylibdir"] + "/" + CONFIG["arch"] $CFLAGS += " -I " + (make_expand CONFIG["archdir"]) LOG = File.open "./config.log", "w" #--------------------------------# DUAL = Object.new DUAL.instance_eval { def self.print x LOG .puts x; LOG .flush STDERR.print x; STDERR.flush end def self.puts x self.print x+"\n" end } def try feature if Or===feature.uses_so k=1 for i in feature.uses_so.a do e=feature.dup e.uses_so i e.name(e.name+" (try \##{k})") r=try e return r if r k+=1 end return false end if Or===feature.uses_h for i in feature.uses_h.a do e=feature.dup e.uses_h i e.name(e.name+" <#{e.uses_h}>") r=try e return r if r end return false end LOG.puts "", "-"*64 DUAL.print "[#{feature.tag}] #{feature.name}: " (feature.uses_feature||[]).find {|f| if Or===f f.a.find {|x| $conf[:FEATURES][x] } or DUAL.puts "disabled (would need #{f})" else if not $conf[:FEATURES][f] DUAL.puts "disabled (would need #{f})" return end end } if feature.status == :disabled DUAL.puts "disabled (by author)" return end if not $features_h[feature.tag] DUAL.puts "disabled (by user)" return end fu = feature.unless_feature || [] fu = [fu] if not Array===fu for f in fu || [] do if $conf[:FEATURES][f] then DUAL.puts "disabled (using #{f} instead)" return end end if feature.test if feature.test.call(feature) DUAL.puts "found" else DUAL.puts "missing" return false end else puts "enabled" $conf[:FEATURES][feature.tag] = feature feature.action.call if feature.action end feature.action.call if feature.action $conf[:FEATURES][feature.tag] = feature $conf[:LDSOFLAGS].concat(feature.uses_so||[]) $conf[:BRIDGE_LDFLAGS].concat(feature.uses_bridge_so||[]) $conf[:OBJS].concat(feature.uses_o||[]) $conf[:FORMATS].concat(feature.formats||[]) $conf[:OPTIONS].concat(feature.options||[]) for k,v in feature.defines||{} do $conf[:DEFINES][k]=(if Proc===v then v[] else v end) end true end DUAL.puts "This is the GridFlow 0.7.3 configurator within Ruby version #{VERSION}" begin $features.each {|feature| try feature } ensure system "/bin/rm -f /tmp/#{$$} /tmp/#{$$}.c" end $conf[:LDSOFLAGS].uniq! $conf[:BRIDGE_LDFLAGS].uniq! #--------------------------------# puts "" for z in [:BRIDGE_LDFLAGS, :LDSOFLAGS, :FORMATS, :OPTIONS, :DEFINES, :OBJS] do puts "#{z}: #{$conf[z].inspect}" end puts "" #--------------------------------# # extconf.rb RUBY = "ruby" def my_install_files(f,base,entries) entries.each {|type,name,*rest| case type when :ruby f.puts "\t$(INSTALL_DATA) #{base+name} $(sitelibdir)/gridflow/#{base+name}" when :directory f.puts "\t$(INSTALL_DIR) $(sitelibdir)/gridflow/#{base+name}" my_install_files(f,base+name,rest) end } end def my_uninstall_files(f,base,entries) entries.each {|type,name,*rest| case type when :ruby f.puts "\trm $(sitelibdir)/gridflow/#{base+name}" when :directory my_uninstall_files(f,base+name,rest) end } end def make_makefile f # f.puts "RUBYDESTDIR2 = " + make_expand(sprintf("%s/%s.%s", # $conf[:DEFINES][:RUBY_PREFIX],CONFIG['MAJOR'],CONFIG['MINOR'])) puts "" f.puts "RUBY = #{RUBY}" f.puts "ruby-all::", "" # f.puts "Makefile: extconf.rb", "\t$(RUBY) extconf.rb", "" f.puts "ruby-install::" my_install_files(f,"",FILES) f.puts f.puts "ruby-uninstall::" my_uninstall_files(f,"",FILES) f.puts end puts "generating ./config.make" File.open("./config.make","w") {|f| f.puts " RUBYARCH=#{CONFIG['arch']} " f.puts "BRIDGE_LDFLAGS = " + $conf[:BRIDGE_LDFLAGS].join(" ") + " " + $LDFLAGS if Config::CONFIG["arch"] =~ /darwin/ then f.puts "BRIDGE_LDFLAGS += -bundle -flat_namespace" else f.puts "BRIDGE_LDFLAGS += -rdynamic -shared" end f.puts "CFLAGS += " + $CFLAGS for k in $conf[:OPTIONS] do f.puts "#{k}=yes" end for k,v in $conf[:DEFINES] do f.puts "#{k}=#{v}" end $sources = %w( base/grid.c base/main.c base/number.c base/bitpacking.c base/flow_objects.c base/flow_objects_for_image.c base/flow_objects_for_matrix.c ) for format in $conf[:FORMATS] do $sources << "format/#{format.downcase}.c" end f.puts "SOURCES = #{$sources.join(" ")} \\" f.puts "" #make_makefile f } # end open config.make #--------------------------------# puts "generating config.h" File.open("config.h","w") {|f| f.puts " \#ifndef __CONFIG_H \#define __CONFIG_H /* this file was auto-generated by gridflow/configure */ " if $conf[:FORMATS]!=[] then f.puts "#define FORMAT_LIST(_pre_,_pre2_,_post_) \\" f.puts $conf[:FORMATS].map {|fmt| " _pre_ _pre2_##Format#{fmt}##_post_" }.join(",\\\n") end for k in $conf[:OPTIONS] do f.puts "\#define #{k}" end for k,v in $conf[:DEFINES] do f.puts "\#define #{k} \"#{v}\"" end if $conf[:FEATURES][:mpeg3] f.puts " \#ifdef LIBMPEG_INCLUDE_HERE \#include <#{$conf[:FEATURES][:mpeg3].uses_h}> \#endif " end f.puts " #endif /* __CONFIG_H */" } puts "", "please see ./config.log for the details of the configuration tests", "" #--------------------------------# $LOCAL_LIBS = $conf[:LDSOFLAGS].join(" ") $objs = $sources.collect{|i| i.sub(/.c$/,".o") } dir_config("gridflow") #p $rubylibdir create_makefile("gridflow") #p $rubylibdir mf = File.readlines("Makefile").join"" #p mf.length common_deps1 = "config.make Makefile Makefile.gf base/source_filter.rb" common_deps2 = common_deps1 + " base/grid.h.fcs" mf.sub!(/^.c.o:\s*\n\t(.*)\n/) { comp=$1 comp.sub!(/\(CC\)/,'(CXX)') comp << " -o $@" if not comp =~ /-o\s*\$@/ "%.h.fcs: %.h #{common_deps1}\n"+ "\truby base/source_filter.rb $< $@\n\n"+ "%.c.fcs: %.c #{common_deps2}\n"+ "\truby base/source_filter.rb $< $@\n\n"+ "%.o: %.c.fcs #{common_deps2}\n"+ "\ttime #{comp}\n" } mf.gsub!(/^.SUFFIXES:.*$/, ".SUFFIXES:\n\n") or mf<<".SUFFIXES:\n\n" mf << ".PRECIOUS: %.h.fcs %.c.fcs" mf.gsub! /DESTDIR/, 'RUBYDESTDIR' mf.gsub! /\*\.o/, "*.o */*.o" mf.gsub!(/^((site-)?install:.*)/) {$1+" install2"} #mf.gsub!(/^install:.*/) {"install:site-install"} # should i keep this line? mf.sub!(/^all:(.*)$/) { "all: #{$1} all2" } mf.sub! /^clean:/,"clean: clean2 " mf.sub! /CC = gcc\n/, "CC = gcc\nCXX = #{$conf[:CC]}\n" mf.sub! /^(OBJS = .*)$/, "\\1 #{$conf[:OBJS].join' '}" mf.sub! /^sitedir = .*$/, "sitedir = " + make_expand($conf[:DEFINES][:RUBY_PREFIX]) #mf.sub! /^LDSHARED = g?cc/, "LDSHARED = " + # (if Config::CONFIG["arch"] =~ /darwin/ # then "cc -dynamic -bundle -undefined suppress -flat_namespace" # else "$(CXX)" end) mf.sub! /^LDSHARED = g?cc/, "LDSHARED = $(CXX)" # Adam Lindsay's Mac attempts. mf.sub! /-no-precomp/, "-no-cpp-precomp" # remove gcc3.2 warning about -I/usr/include mf.sub!(/^CPPFLAGS = (.*)$/) { cpp = "CPPFLAGS = " + make_expand($1).sub(%r"-I\s*/usr/include","") } # jMax conflict resolution (this must be done last) mf.gsub!(/prefix/,'rubyprefix') #p mf.length f = File.open("Makefile","w") f.puts "include config.make" f.puts mf f.puts "include Makefile.gf" make_makefile f f.close # puts "$CFLAGS = #{$CFLAGS.inspect}" =begin for z in [ :$srcdir, :$libdir, :$rubylibdir, :$archdir, :$sitedir, :$sitelibdir, :$sitearchdir, :$prefix, :$exec_prefix, ] do puts "#{z} = #{eval z.to_s}" end =end END { system "rm -f /tmp/#{$$}.cpp /tmp/#{$$}" }