reno 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +24 -0
- data/reno.rb +20 -0
- data/reno/builder.rb +136 -0
- data/reno/cache.rb +57 -0
- data/reno/configuration.rb +50 -0
- data/reno/languages.rb +61 -0
- data/reno/languages/c.rb +156 -0
- data/reno/lock.rb +33 -0
- data/reno/options.rb +89 -0
- data/reno/package.rb +82 -0
- data/reno/platforms.rb +17 -0
- data/reno/sourcefile.rb +139 -0
- data/reno/toolchains.rb +39 -0
- data/reno/toolchains/gnu.rb +53 -0
- metadata +68 -0
    
        data/LICENSE
    ADDED
    
    | @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            Copyright (c) 2010, Zoxc
         | 
| 2 | 
            +
            All rights reserved.
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Redistribution and use in source and binary forms, with or without
         | 
| 5 | 
            +
            modification, are permitted provided that the following conditions are met:
         | 
| 6 | 
            +
                * Redistributions of source code must retain the above copyright
         | 
| 7 | 
            +
                  notice, this list of conditions and the following disclaimer.
         | 
| 8 | 
            +
                * Redistributions in binary form must reproduce the above copyright
         | 
| 9 | 
            +
                  notice, this list of conditions and the following disclaimer in the
         | 
| 10 | 
            +
                  documentation and/or other materials provided with the distribution.
         | 
| 11 | 
            +
                * Neither the name of Zoxc nor the
         | 
| 12 | 
            +
                  names of its contributors may be used to endorse or promote products
         | 
| 13 | 
            +
                  derived from this software without specific prior written permission.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
         | 
| 16 | 
            +
            ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
         | 
| 17 | 
            +
            WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
         | 
| 18 | 
            +
            DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
         | 
| 19 | 
            +
            DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
         | 
| 20 | 
            +
            (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
         | 
| 21 | 
            +
            LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
         | 
| 22 | 
            +
            ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
         | 
| 23 | 
            +
            (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
         | 
| 24 | 
            +
            SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         | 
    
        data/reno.rb
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            module Reno
         | 
| 2 | 
            +
            	require 'rexml/document'
         | 
| 3 | 
            +
            	
         | 
| 4 | 
            +
            	ROOT = File.dirname(File.expand_path(__FILE__)) unless defined?(Reno::ROOT)
         | 
| 5 | 
            +
             
         | 
| 6 | 
            +
            	unless $LOAD_PATH.any? { |lp| File.expand_path(lp) == ROOT }
         | 
| 7 | 
            +
            		$LOAD_PATH.unshift(ROOT)
         | 
| 8 | 
            +
            	end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            	require 'reno/lock'
         | 
| 11 | 
            +
            	require 'reno/configuration'
         | 
| 12 | 
            +
            	require 'reno/builder'
         | 
| 13 | 
            +
            	require 'reno/cache'
         | 
| 14 | 
            +
            	require 'reno/platforms'
         | 
| 15 | 
            +
            	require 'reno/sourcefile'
         | 
| 16 | 
            +
            	require 'reno/options'
         | 
| 17 | 
            +
            	require 'reno/languages'
         | 
| 18 | 
            +
            	require 'reno/toolchains'
         | 
| 19 | 
            +
            	require 'reno/package'
         | 
| 20 | 
            +
            end
         | 
    
        data/reno/builder.rb
    ADDED
    
    | @@ -0,0 +1,136 @@ | |
| 1 | 
            +
            require 'pathname'
         | 
| 2 | 
            +
            require 'fileutils'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Reno
         | 
| 5 | 
            +
            	class BuilderError < StandardError
         | 
| 6 | 
            +
            	end
         | 
| 7 | 
            +
            	
         | 
| 8 | 
            +
            	class Builder
         | 
| 9 | 
            +
            		attr_reader :sources, :cache, :sqlcache, :base, :output, :objects, :package, :conf
         | 
| 10 | 
            +
            		attr :conf, true
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            		def self.readydirs(path)
         | 
| 13 | 
            +
            			FileUtils.makedirs(File.dirname(path))
         | 
| 14 | 
            +
            		end
         | 
| 15 | 
            +
            		
         | 
| 16 | 
            +
            		def self.cleanpath(base, path)
         | 
| 17 | 
            +
            			Pathname.new(File.expand_path(path)).relative_path_from(Pathname.new(base)).to_s
         | 
| 18 | 
            +
            		end
         | 
| 19 | 
            +
            		
         | 
| 20 | 
            +
            		def self.execute(command, *args)
         | 
| 21 | 
            +
            			#puts [command, *args].join(' ')
         | 
| 22 | 
            +
            			IO.popen([command, *args]) do |f|
         | 
| 23 | 
            +
            				f.readlines
         | 
| 24 | 
            +
            			end
         | 
| 25 | 
            +
            			raise "#{command} failed with error code #{$?.exitstatus}" if $?.exitstatus != 0
         | 
| 26 | 
            +
            		end
         | 
| 27 | 
            +
            		
         | 
| 28 | 
            +
            		def self.capture(command, *args)
         | 
| 29 | 
            +
            			#puts [command, *args].join(' ')
         | 
| 30 | 
            +
            			result = nil
         | 
| 31 | 
            +
            			IO.popen([command, *args]) do |f|
         | 
| 32 | 
            +
            				result = f.readlines.join('')
         | 
| 33 | 
            +
            			end
         | 
| 34 | 
            +
            			raise "#{command} failed with error code #{$?.exitstatus}" if $?.exitstatus != 0
         | 
| 35 | 
            +
            			result
         | 
| 36 | 
            +
            		end
         | 
| 37 | 
            +
            	 
         | 
| 38 | 
            +
            		def self.clean(filename)
         | 
| 39 | 
            +
            			if File.exists?(filename)
         | 
| 40 | 
            +
            				File.delete(filename)
         | 
| 41 | 
            +
            				begin
         | 
| 42 | 
            +
            					dir = File.dirname(filename)
         | 
| 43 | 
            +
            					while File.exists?(dir)
         | 
| 44 | 
            +
            						Dir.rmdir(dir)
         | 
| 45 | 
            +
            						dir = File.dirname(dir)
         | 
| 46 | 
            +
            					end
         | 
| 47 | 
            +
            				rescue SystemCallError
         | 
| 48 | 
            +
            				end
         | 
| 49 | 
            +
            			end
         | 
| 50 | 
            +
            		end
         | 
| 51 | 
            +
            		
         | 
| 52 | 
            +
            		def puts(*args)
         | 
| 53 | 
            +
            			@puts_lock.synchronize do
         | 
| 54 | 
            +
            				Kernel.puts *args
         | 
| 55 | 
            +
            			end
         | 
| 56 | 
            +
            		end
         | 
| 57 | 
            +
            		
         | 
| 58 | 
            +
            		def output(file)
         | 
| 59 | 
            +
            			result = File.expand_path(file, @bulid_base)
         | 
| 60 | 
            +
            			Builder.readydirs(result)
         | 
| 61 | 
            +
            			result
         | 
| 62 | 
            +
            		end
         | 
| 63 | 
            +
            		
         | 
| 64 | 
            +
            		def initialize(package)
         | 
| 65 | 
            +
            			@package = package
         | 
| 66 | 
            +
            			@changed = Lock.new
         | 
| 67 | 
            +
            			@base = @package.base
         | 
| 68 | 
            +
            			@bulid_base = File.expand_path(@package.output, @base)
         | 
| 69 | 
            +
            			@objects = Lock.new([])
         | 
| 70 | 
            +
            			@files = Lock.new([])
         | 
| 71 | 
            +
            			@puts_lock = Mutex.new
         | 
| 72 | 
            +
            			@cache =  Lock.new({})
         | 
| 73 | 
            +
            		end
         | 
| 74 | 
            +
            		
         | 
| 75 | 
            +
            		def run(threads = 8)
         | 
| 76 | 
            +
            			# Creates an unique list of the files
         | 
| 77 | 
            +
            			@files.value = Dir[*@conf.get(:patterns)].map { |file| Builder.cleanpath(@base, file) }.uniq
         | 
| 78 | 
            +
            			@sqlcache = Cache.new(self)
         | 
| 79 | 
            +
            			
         | 
| 80 | 
            +
            			# Start worker threads	
         | 
| 81 | 
            +
            			workers = []
         | 
| 82 | 
            +
            			threads.times do
         | 
| 83 | 
            +
            				workers << Thread.new do
         | 
| 84 | 
            +
            					work
         | 
| 85 | 
            +
            				end
         | 
| 86 | 
            +
            			end
         | 
| 87 | 
            +
            			
         | 
| 88 | 
            +
            			# Wait for all the workers
         | 
| 89 | 
            +
            			workers.each { |worker| worker.join }
         | 
| 90 | 
            +
            			
         | 
| 91 | 
            +
            			# Normalize locks
         | 
| 92 | 
            +
            			@objects = @objects.value
         | 
| 93 | 
            +
            			
         | 
| 94 | 
            +
            			# Link the package if it changed or the output doesn't exist
         | 
| 95 | 
            +
            			
         | 
| 96 | 
            +
            			output_name = output(package.output_name)
         | 
| 97 | 
            +
            			
         | 
| 98 | 
            +
            			if @changed.value || !File.exists?(output_name)
         | 
| 99 | 
            +
            				puts "Linking #{@package.name}..."
         | 
| 100 | 
            +
            				
         | 
| 101 | 
            +
            				# Find a toochain to link this package
         | 
| 102 | 
            +
            				linker = @package.default[:linker]
         | 
| 103 | 
            +
            				linker = Toolchains::Hash.values.first unless linker
         | 
| 104 | 
            +
            				raise BuilderError, "Unable to find a linker to use." unless linker
         | 
| 105 | 
            +
            				
         | 
| 106 | 
            +
            				linker.link(self, output(package.output_name))
         | 
| 107 | 
            +
            			else
         | 
| 108 | 
            +
            				puts "Nothing to do with #{@package.name}."
         | 
| 109 | 
            +
            			end
         | 
| 110 | 
            +
            		end
         | 
| 111 | 
            +
            		
         | 
| 112 | 
            +
            		def get_file
         | 
| 113 | 
            +
            			@files.lock do |files|
         | 
| 114 | 
            +
            				files.pop
         | 
| 115 | 
            +
            			end
         | 
| 116 | 
            +
            		end
         | 
| 117 | 
            +
            		
         | 
| 118 | 
            +
            		def output_file(result)
         | 
| 119 | 
            +
            			@objects.lock do |output|
         | 
| 120 | 
            +
            				output << result
         | 
| 121 | 
            +
            			end
         | 
| 122 | 
            +
            		end
         | 
| 123 | 
            +
            		
         | 
| 124 | 
            +
            		def work
         | 
| 125 | 
            +
            			while filename = get_file
         | 
| 126 | 
            +
            				file = SourceFile.locate(self, filename)
         | 
| 127 | 
            +
            				rebuild = file.rebuild?
         | 
| 128 | 
            +
            				if rebuild
         | 
| 129 | 
            +
            					@changed.value = true
         | 
| 130 | 
            +
            					file.build
         | 
| 131 | 
            +
            				end
         | 
| 132 | 
            +
            				output_file file
         | 
| 133 | 
            +
            			end
         | 
| 134 | 
            +
            		end
         | 
| 135 | 
            +
            	end
         | 
| 136 | 
            +
            end
         | 
    
        data/reno/cache.rb
    ADDED
    
    | @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require 'pathname'
         | 
| 2 | 
            +
            require 'sequel'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Reno
         | 
| 5 | 
            +
            	class Cache
         | 
| 6 | 
            +
            		attr_reader :base, :db
         | 
| 7 | 
            +
            		
         | 
| 8 | 
            +
            		class FileModel
         | 
| 9 | 
            +
            			def initialize(db, name, &block)
         | 
| 10 | 
            +
            				@db = db
         | 
| 11 | 
            +
            				@row = @db[:name => name]
         | 
| 12 | 
            +
            				unless @row
         | 
| 13 | 
            +
            					@row = block.call
         | 
| 14 | 
            +
            					@row[:id] = @db.insert(@row)
         | 
| 15 | 
            +
            				end
         | 
| 16 | 
            +
            			end
         | 
| 17 | 
            +
            			
         | 
| 18 | 
            +
            			def [](name)
         | 
| 19 | 
            +
            				@row[name]
         | 
| 20 | 
            +
            			end
         | 
| 21 | 
            +
            			
         | 
| 22 | 
            +
            			def []=(name, value)
         | 
| 23 | 
            +
            				@row[name] = value
         | 
| 24 | 
            +
            				@db.filter(:id => @row[:id]).update(name => value)
         | 
| 25 | 
            +
            			end
         | 
| 26 | 
            +
            		end
         | 
| 27 | 
            +
            		
         | 
| 28 | 
            +
            		def setup_table(name, &block)
         | 
| 29 | 
            +
            			@db.create_table(name, &block) unless @db.table_exists?(name)
         | 
| 30 | 
            +
            		end
         | 
| 31 | 
            +
            		
         | 
| 32 | 
            +
            		def initialize(builder)
         | 
| 33 | 
            +
            			@db = Sequel.sqlite(:database => builder.output('cache.db'))
         | 
| 34 | 
            +
            			
         | 
| 35 | 
            +
            			setup_table :files do
         | 
| 36 | 
            +
            				primary_key :id, :type => Integer
         | 
| 37 | 
            +
            				String :name
         | 
| 38 | 
            +
            				String :md5
         | 
| 39 | 
            +
            				String :output
         | 
| 40 | 
            +
            				FalseClass :dependencies
         | 
| 41 | 
            +
            			end
         | 
| 42 | 
            +
            			
         | 
| 43 | 
            +
            			setup_table :dependencies do
         | 
| 44 | 
            +
            				Integer :file
         | 
| 45 | 
            +
            				Integer :dependency
         | 
| 46 | 
            +
            			end
         | 
| 47 | 
            +
            			
         | 
| 48 | 
            +
            			Languages.constants.each do |language|
         | 
| 49 | 
            +
            				language = Languages.const_get(language)
         | 
| 50 | 
            +
            				
         | 
| 51 | 
            +
            				next if language.superclass != Languages::Language
         | 
| 52 | 
            +
            				
         | 
| 53 | 
            +
            				language.setup_schema(self)
         | 
| 54 | 
            +
            			end
         | 
| 55 | 
            +
            		end
         | 
| 56 | 
            +
            	end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            module Reno
         | 
| 2 | 
            +
            	class ConfigurationError < StandardError
         | 
| 3 | 
            +
            	end
         | 
| 4 | 
            +
            	
         | 
| 5 | 
            +
            	class ConfigurationNode
         | 
| 6 | 
            +
            		attr_reader :langs, :builder, :parent, :hash, :patterns
         | 
| 7 | 
            +
            		
         | 
| 8 | 
            +
            		def initialize(package, builder, parent, patterns)
         | 
| 9 | 
            +
            			@package = package
         | 
| 10 | 
            +
            			@builder = builder
         | 
| 11 | 
            +
            			@parent = parent
         | 
| 12 | 
            +
            			@patterns = patterns.to_a
         | 
| 13 | 
            +
            			@children = []
         | 
| 14 | 
            +
            			@hash = {}
         | 
| 15 | 
            +
            		end
         | 
| 16 | 
            +
            		
         | 
| 17 | 
            +
            		def add(name, values)
         | 
| 18 | 
            +
            			@hash[name] = [] unless @hash.has_key?(name)
         | 
| 19 | 
            +
            			@hash[name].concat(values)
         | 
| 20 | 
            +
            		end
         | 
| 21 | 
            +
            		
         | 
| 22 | 
            +
            		def get(name, file = nil, base = nil)
         | 
| 23 | 
            +
            			if file && !@patterns.empty?
         | 
| 24 | 
            +
            				Dir.chdir(base) do
         | 
| 25 | 
            +
            					return nil unless @patterns.any? { |pattern| File.fnmatch?(pattern, file) }
         | 
| 26 | 
            +
            				end
         | 
| 27 | 
            +
            			end
         | 
| 28 | 
            +
            			
         | 
| 29 | 
            +
            			child_values = []
         | 
| 30 | 
            +
            			
         | 
| 31 | 
            +
            			@children.each do |child|
         | 
| 32 | 
            +
            				child_values.concat(child.get(name, file).reject { |value| !value })
         | 
| 33 | 
            +
            			end
         | 
| 34 | 
            +
            			
         | 
| 35 | 
            +
            			if Array === @hash[name]
         | 
| 36 | 
            +
            				@hash[name] + child_values
         | 
| 37 | 
            +
            			else
         | 
| 38 | 
            +
            				child_values
         | 
| 39 | 
            +
            			end
         | 
| 40 | 
            +
            		end
         | 
| 41 | 
            +
            		
         | 
| 42 | 
            +
            		def derive(patterns)
         | 
| 43 | 
            +
            			patterns = patterns.to_a
         | 
| 44 | 
            +
            			child = ConfigurationNode.new(@package, @builder, self, patterns)
         | 
| 45 | 
            +
            			child.add(:patterns, patterns)
         | 
| 46 | 
            +
            			@children << child
         | 
| 47 | 
            +
            			child
         | 
| 48 | 
            +
            		end
         | 
| 49 | 
            +
            	end
         | 
| 50 | 
            +
            end
         | 
    
        data/reno/languages.rb
    ADDED
    
    | @@ -0,0 +1,61 @@ | |
| 1 | 
            +
            module Reno
         | 
| 2 | 
            +
            	module Languages
         | 
| 3 | 
            +
            		class LanguageError < StandardError
         | 
| 4 | 
            +
            		end
         | 
| 5 | 
            +
            		
         | 
| 6 | 
            +
            		def self.locate(name)
         | 
| 7 | 
            +
            			Languages.constants.map { |lang| Languages.const_get(lang) }.each do |language|
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            				next if language.superclass != Language
         | 
| 10 | 
            +
            				
         | 
| 11 | 
            +
            				if language.name == name
         | 
| 12 | 
            +
            					return language
         | 
| 13 | 
            +
            				end
         | 
| 14 | 
            +
            			end
         | 
| 15 | 
            +
            			
         | 
| 16 | 
            +
            			raise "Unable to find the language '#{name}'."
         | 
| 17 | 
            +
            		end
         | 
| 18 | 
            +
            	
         | 
| 19 | 
            +
            		class Language
         | 
| 20 | 
            +
            			attr_reader :option
         | 
| 21 | 
            +
            			
         | 
| 22 | 
            +
            			def inspect
         | 
| 23 | 
            +
            				"#<Language:#{self.class.name}>"
         | 
| 24 | 
            +
            			end
         | 
| 25 | 
            +
            			
         | 
| 26 | 
            +
            			def initialize(option, block)
         | 
| 27 | 
            +
            				@option = option
         | 
| 28 | 
            +
            				instance_eval(&block) if block
         | 
| 29 | 
            +
            			end
         | 
| 30 | 
            +
            			
         | 
| 31 | 
            +
            			def get_dependencies(file)
         | 
| 32 | 
            +
            				[]
         | 
| 33 | 
            +
            			end
         | 
| 34 | 
            +
            			
         | 
| 35 | 
            +
            			def read(name)
         | 
| 36 | 
            +
            				instance_variable_get "@#{name}"
         | 
| 37 | 
            +
            			end
         | 
| 38 | 
            +
            			
         | 
| 39 | 
            +
            			class << self
         | 
| 40 | 
            +
            				attr :name, true
         | 
| 41 | 
            +
            				
         | 
| 42 | 
            +
            				def table_name(name)
         | 
| 43 | 
            +
            					"lang_#{self.name}_#{name}".downcase.to_sym
         | 
| 44 | 
            +
            				end
         | 
| 45 | 
            +
            				
         | 
| 46 | 
            +
            				def setup_table(cache, name, &block)
         | 
| 47 | 
            +
            					cache.setup_table(table_name(name), &block)
         | 
| 48 | 
            +
            				end
         | 
| 49 | 
            +
            				
         | 
| 50 | 
            +
            				def setup_schema(cache)
         | 
| 51 | 
            +
            				end
         | 
| 52 | 
            +
            				
         | 
| 53 | 
            +
            				def merge(nodes)
         | 
| 54 | 
            +
            					result = new(nil, nil)
         | 
| 55 | 
            +
            					nodes.each { |node| result.merge(node) }
         | 
| 56 | 
            +
            					result
         | 
| 57 | 
            +
            				end
         | 
| 58 | 
            +
            			end
         | 
| 59 | 
            +
            		end
         | 
| 60 | 
            +
            	end
         | 
| 61 | 
            +
            end
         | 
    
        data/reno/languages/c.rb
    ADDED
    
    | @@ -0,0 +1,156 @@ | |
| 1 | 
            +
            module Reno
         | 
| 2 | 
            +
            	module Languages
         | 
| 3 | 
            +
            		class C < Language
         | 
| 4 | 
            +
            			self.name = 'C'
         | 
| 5 | 
            +
            			
         | 
| 6 | 
            +
            			def initialize(*args)
         | 
| 7 | 
            +
            				@defines = {}
         | 
| 8 | 
            +
            				@headers = []
         | 
| 9 | 
            +
            				@std = nil
         | 
| 10 | 
            +
            				@strict = nil
         | 
| 11 | 
            +
            				super
         | 
| 12 | 
            +
            			end
         | 
| 13 | 
            +
            			
         | 
| 14 | 
            +
            			def compare(file)
         | 
| 15 | 
            +
            				defines = file.db[self.class.table_name(:defines)]
         | 
| 16 | 
            +
            				attribs = file.db[self.class.table_name(:attribs)]
         | 
| 17 | 
            +
            				
         | 
| 18 | 
            +
            				hash = {}
         | 
| 19 | 
            +
            				
         | 
| 20 | 
            +
            				defines.filter(:file => file.row[:id]).all do |row|
         | 
| 21 | 
            +
            					hash[row[:define]] = row[:value]
         | 
| 22 | 
            +
            				end
         | 
| 23 | 
            +
            				
         | 
| 24 | 
            +
            				attribs = attribs.filter(:file => file.row[:id]).first
         | 
| 25 | 
            +
            				attribs = {:std => nil, :strict => false} unless attribs
         | 
| 26 | 
            +
            				
         | 
| 27 | 
            +
            				hash == @defines and attribs[:std] == @std.to_s and attribs[:strict] == @strict
         | 
| 28 | 
            +
            			end
         | 
| 29 | 
            +
            			
         | 
| 30 | 
            +
            			def print(*values)
         | 
| 31 | 
            +
            				puts values.inspect
         | 
| 32 | 
            +
            			end
         | 
| 33 | 
            +
            			
         | 
| 34 | 
            +
            			def store(file)
         | 
| 35 | 
            +
            				defines = file.db[self.class.table_name(:defines)]
         | 
| 36 | 
            +
            				attribs = file.db[self.class.table_name(:attribs)]
         | 
| 37 | 
            +
            				
         | 
| 38 | 
            +
            				# Delete existing rows				
         | 
| 39 | 
            +
            				defines.filter(:file => file.row[:id]).delete
         | 
| 40 | 
            +
            				attribs.filter(:file => file.row[:id]).delete
         | 
| 41 | 
            +
            				
         | 
| 42 | 
            +
            				# Add the current ones
         | 
| 43 | 
            +
            				@defines.each_pair do |key, value|
         | 
| 44 | 
            +
            					defines.insert(:file => file.row[:id], :define => key, :value => value)
         | 
| 45 | 
            +
            				end
         | 
| 46 | 
            +
            				
         | 
| 47 | 
            +
            				attribs.insert(:file => file.row[:id], :strict => @strict, :std => @std.to_s)
         | 
| 48 | 
            +
            			end
         | 
| 49 | 
            +
            			
         | 
| 50 | 
            +
            			def self.setup_schema(cache)
         | 
| 51 | 
            +
            				setup_table(cache, :defines) do
         | 
| 52 | 
            +
            					Integer :file
         | 
| 53 | 
            +
            					String :define
         | 
| 54 | 
            +
            					String :value
         | 
| 55 | 
            +
            				end
         | 
| 56 | 
            +
            				
         | 
| 57 | 
            +
            				setup_table(cache, :attribs) do
         | 
| 58 | 
            +
            					Integer :file
         | 
| 59 | 
            +
            					FalseClass :strict
         | 
| 60 | 
            +
            					String :std
         | 
| 61 | 
            +
            				end
         | 
| 62 | 
            +
            			end
         | 
| 63 | 
            +
            			
         | 
| 64 | 
            +
            			def merge(other)
         | 
| 65 | 
            +
            				@defines.merge!(other.read(:defines))
         | 
| 66 | 
            +
            				
         | 
| 67 | 
            +
            				other_value = other.read(:std)
         | 
| 68 | 
            +
            				@std = other_value if other_value
         | 
| 69 | 
            +
            				
         | 
| 70 | 
            +
            				other_value = other.read(:strict)
         | 
| 71 | 
            +
            				@strict = other_value if other_value != nil
         | 
| 72 | 
            +
            			end
         | 
| 73 | 
            +
            			
         | 
| 74 | 
            +
            			def define(name, value = nil)
         | 
| 75 | 
            +
            				@defines[name] = value
         | 
| 76 | 
            +
            			end
         | 
| 77 | 
            +
            			
         | 
| 78 | 
            +
            			def strict(value = true)
         | 
| 79 | 
            +
            				@strict = value
         | 
| 80 | 
            +
            			end
         | 
| 81 | 
            +
            			
         | 
| 82 | 
            +
            			def std(value)
         | 
| 83 | 
            +
            				@std = value
         | 
| 84 | 
            +
            			end
         | 
| 85 | 
            +
            			
         | 
| 86 | 
            +
            			def headers(*dirs)
         | 
| 87 | 
            +
            				@headers.concat(dirs)
         | 
| 88 | 
            +
            			end
         | 
| 89 | 
            +
            			
         | 
| 90 | 
            +
            			def self.extensions
         | 
| 91 | 
            +
            				['.c', '.h']
         | 
| 92 | 
            +
            			end
         | 
| 93 | 
            +
            			
         | 
| 94 | 
            +
            			# The get_dependencies method is under the GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 license.
         | 
| 95 | 
            +
            			# It's from rant-0.5.8\lib\rant\c\include.rb
         | 
| 96 | 
            +
            			
         | 
| 97 | 
            +
            			# include.rb - Support for C - parsing #include statements.
         | 
| 98 | 
            +
            			#
         | 
| 99 | 
            +
            			# Copyright (C) 2005 Stefan Lang <langstefan@gmx.at>
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            			
         | 
| 102 | 
            +
            			# Searches for all `#include' statements in the C/C++ source
         | 
| 103 | 
            +
            			# from the string +src+.
         | 
| 104 | 
            +
            			#
         | 
| 105 | 
            +
            			# Returns two arguments:
         | 
| 106 | 
            +
            			# 1. A list of all standard library includes (e.g. #include <stdio.h>).
         | 
| 107 | 
            +
            			# 2. A list of all local includes (e.g. #include "stdio.h").
         | 
| 108 | 
            +
            			
         | 
| 109 | 
            +
            			def self.get_dependencies(file)
         | 
| 110 | 
            +
            				src = file.content
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            				includes = []
         | 
| 113 | 
            +
            				in_block_comment = false
         | 
| 114 | 
            +
            				prev_line = nil
         | 
| 115 | 
            +
            				
         | 
| 116 | 
            +
            				src.each_line do |line|
         | 
| 117 | 
            +
            					line.chomp!
         | 
| 118 | 
            +
            					
         | 
| 119 | 
            +
            					if block_start_i = line.index("/*")
         | 
| 120 | 
            +
            						c_start_i = line.index("//")
         | 
| 121 | 
            +
            						if !c_start_i || block_start_i < c_start_i
         | 
| 122 | 
            +
            							if block_end_i = line.index("*/")
         | 
| 123 | 
            +
            								if block_end_i > block_start_i
         | 
| 124 | 
            +
            									line[block_start_i..block_end_i+1] = ""
         | 
| 125 | 
            +
            								end
         | 
| 126 | 
            +
            							end
         | 
| 127 | 
            +
            						end
         | 
| 128 | 
            +
            					end
         | 
| 129 | 
            +
            					
         | 
| 130 | 
            +
            					if prev_line
         | 
| 131 | 
            +
            						line = prev_line << line
         | 
| 132 | 
            +
            						prev_line = nil
         | 
| 133 | 
            +
            					end
         | 
| 134 | 
            +
            					
         | 
| 135 | 
            +
            					if line =~ /\\$/
         | 
| 136 | 
            +
            						prev_line = line.chomp[0...line.length-1]
         | 
| 137 | 
            +
            					end
         | 
| 138 | 
            +
            					
         | 
| 139 | 
            +
            					if in_block_comment
         | 
| 140 | 
            +
            						in_block_comment = false if line =~ %r|\*/|
         | 
| 141 | 
            +
            						next
         | 
| 142 | 
            +
            					end
         | 
| 143 | 
            +
            					
         | 
| 144 | 
            +
            					case line
         | 
| 145 | 
            +
            						when /\s*#\s*include\s+"([^"]+)"/
         | 
| 146 | 
            +
            							includes << $1
         | 
| 147 | 
            +
            						when %r|(?!//)[^/]*/\*|
         | 
| 148 | 
            +
            							in_block_comment = true
         | 
| 149 | 
            +
            					end
         | 
| 150 | 
            +
            				end
         | 
| 151 | 
            +
            				
         | 
| 152 | 
            +
            				includes
         | 
| 153 | 
            +
            			end
         | 
| 154 | 
            +
            		end
         | 
| 155 | 
            +
            	end
         | 
| 156 | 
            +
            end
         | 
    
        data/reno/lock.rb
    ADDED
    
    | @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            module Reno
         | 
| 2 | 
            +
            	class Lock
         | 
| 3 | 
            +
            		def initialize(value = nil)
         | 
| 4 | 
            +
            			@value = value
         | 
| 5 | 
            +
            			@mutex = Mutex.new
         | 
| 6 | 
            +
            		end
         | 
| 7 | 
            +
            		
         | 
| 8 | 
            +
            		def lock
         | 
| 9 | 
            +
            			@mutex.synchronize do
         | 
| 10 | 
            +
            				yield @value
         | 
| 11 | 
            +
            			end
         | 
| 12 | 
            +
            		end
         | 
| 13 | 
            +
            		
         | 
| 14 | 
            +
            		def value
         | 
| 15 | 
            +
            			if block_given?
         | 
| 16 | 
            +
            				@mutex.synchronize do
         | 
| 17 | 
            +
            					return @value if @value
         | 
| 18 | 
            +
            					@value = yield
         | 
| 19 | 
            +
            				end
         | 
| 20 | 
            +
            			else
         | 
| 21 | 
            +
            				@mutex.synchronize do
         | 
| 22 | 
            +
            					@value
         | 
| 23 | 
            +
            				end
         | 
| 24 | 
            +
            			end
         | 
| 25 | 
            +
            		end
         | 
| 26 | 
            +
            		
         | 
| 27 | 
            +
            		def value=(value)
         | 
| 28 | 
            +
            			@mutex.synchronize do
         | 
| 29 | 
            +
            				@value = value
         | 
| 30 | 
            +
            			end
         | 
| 31 | 
            +
            		end
         | 
| 32 | 
            +
            	end
         | 
| 33 | 
            +
            end
         | 
    
        data/reno/options.rb
    ADDED
    
    | @@ -0,0 +1,89 @@ | |
| 1 | 
            +
            module Reno
         | 
| 2 | 
            +
            	class Option
         | 
| 3 | 
            +
            		attr_reader :package, :parent, :name, :desc, :children
         | 
| 4 | 
            +
            		
         | 
| 5 | 
            +
            		def initialize(package, parent, name = nil, desc = nil, default = nil, block)
         | 
| 6 | 
            +
            			@package = package
         | 
| 7 | 
            +
            			@parent = parent
         | 
| 8 | 
            +
            			@name = name
         | 
| 9 | 
            +
            			@desc = desc
         | 
| 10 | 
            +
            			@default = default
         | 
| 11 | 
            +
            			@children = []
         | 
| 12 | 
            +
            			@langs = {}
         | 
| 13 | 
            +
            			instance_eval(&block) if block
         | 
| 14 | 
            +
            		end
         | 
| 15 | 
            +
            		
         | 
| 16 | 
            +
            		def apply_config(conf, data)
         | 
| 17 | 
            +
            			conf.add(:langs, [@langs])
         | 
| 18 | 
            +
            			@children.each do |child|
         | 
| 19 | 
            +
            				child_data = data.elements.find { |element| element.attribute('name').value == child.name.to_s && element.name == child.xml_node } if data
         | 
| 20 | 
            +
            				child.apply_config(conf, child_data)
         | 
| 21 | 
            +
            			end
         | 
| 22 | 
            +
            		end
         | 
| 23 | 
            +
            		
         | 
| 24 | 
            +
            		def xml_node
         | 
| 25 | 
            +
            			"group"
         | 
| 26 | 
            +
            		end
         | 
| 27 | 
            +
            		
         | 
| 28 | 
            +
            		def o(name, desc = nil, default = false, &block)
         | 
| 29 | 
            +
            			@children << BooleanOption.new(@package, self, name, desc, default, block)
         | 
| 30 | 
            +
            		end
         | 
| 31 | 
            +
            		
         | 
| 32 | 
            +
            		def group(name, desc = nil, &block)
         | 
| 33 | 
            +
            			@children << Option.new(@package, self, name, desc, block)
         | 
| 34 | 
            +
            		end
         | 
| 35 | 
            +
            		
         | 
| 36 | 
            +
            		def source(*args, &block)
         | 
| 37 | 
            +
            			@children << SourceOption.new(@package, self, block, args)
         | 
| 38 | 
            +
            		end
         | 
| 39 | 
            +
            		
         | 
| 40 | 
            +
            		alias :sources :source
         | 
| 41 | 
            +
            		
         | 
| 42 | 
            +
            		def default(hash)
         | 
| 43 | 
            +
            			@package.default.merge!(hash)
         | 
| 44 | 
            +
            		end
         | 
| 45 | 
            +
            		
         | 
| 46 | 
            +
            		def lang(name = nil, &block)
         | 
| 47 | 
            +
            			lang = name || @package.default[:lang]
         | 
| 48 | 
            +
            			
         | 
| 49 | 
            +
            			raise "Unable to find the default language." unless lang
         | 
| 50 | 
            +
            			
         | 
| 51 | 
            +
            			lang = lang.to_s
         | 
| 52 | 
            +
            			
         | 
| 53 | 
            +
            			return @langs[lang] if @langs[lang]
         | 
| 54 | 
            +
            			
         | 
| 55 | 
            +
            			obj = Languages.locate(lang).new(self, block)
         | 
| 56 | 
            +
            			@langs[lang] = obj
         | 
| 57 | 
            +
            			obj
         | 
| 58 | 
            +
            		end
         | 
| 59 | 
            +
            	end
         | 
| 60 | 
            +
            	
         | 
| 61 | 
            +
            	class BooleanOption < Option
         | 
| 62 | 
            +
            		def apply_config(conf, data)
         | 
| 63 | 
            +
            			if (data && data.attribute('value')) ? data.attribute('value').value == "true" : @default
         | 
| 64 | 
            +
            				super
         | 
| 65 | 
            +
            			end
         | 
| 66 | 
            +
            		end
         | 
| 67 | 
            +
            		
         | 
| 68 | 
            +
            		def xml_node
         | 
| 69 | 
            +
            			"option"
         | 
| 70 | 
            +
            		end
         | 
| 71 | 
            +
            		
         | 
| 72 | 
            +
            	end
         | 
| 73 | 
            +
            	
         | 
| 74 | 
            +
            	class SourceOption < Option
         | 
| 75 | 
            +
            		def initialize(*args, sources)
         | 
| 76 | 
            +
            			@sources = sources
         | 
| 77 | 
            +
            			super *args
         | 
| 78 | 
            +
            		end
         | 
| 79 | 
            +
            		
         | 
| 80 | 
            +
            		def apply_config(conf, data)
         | 
| 81 | 
            +
            			conf = conf.derive(@sources)
         | 
| 82 | 
            +
            			super
         | 
| 83 | 
            +
            		end
         | 
| 84 | 
            +
            		
         | 
| 85 | 
            +
            		def xml_node
         | 
| 86 | 
            +
            			"file"
         | 
| 87 | 
            +
            		end
         | 
| 88 | 
            +
            	end
         | 
| 89 | 
            +
            end
         | 
    
        data/reno/package.rb
    ADDED
    
    | @@ -0,0 +1,82 @@ | |
| 1 | 
            +
            module Reno
         | 
| 2 | 
            +
            	class PackageError < StandardError
         | 
| 3 | 
            +
            	end
         | 
| 4 | 
            +
            	
         | 
| 5 | 
            +
            	Packages = {}
         | 
| 6 | 
            +
            	
         | 
| 7 | 
            +
            	class PackageOption < Option
         | 
| 8 | 
            +
            		def name(name)
         | 
| 9 | 
            +
            			@package.name = name
         | 
| 10 | 
            +
            		end
         | 
| 11 | 
            +
            		
         | 
| 12 | 
            +
            		def desc(desc)
         | 
| 13 | 
            +
            			@package.desc = desc
         | 
| 14 | 
            +
            		end
         | 
| 15 | 
            +
            		
         | 
| 16 | 
            +
            		def version(version)
         | 
| 17 | 
            +
            			@package.version = version
         | 
| 18 | 
            +
            		end
         | 
| 19 | 
            +
            	end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            	class Package
         | 
| 22 | 
            +
            		attr_reader :default, :name, :base, :output
         | 
| 23 | 
            +
            		attr :desc, true
         | 
| 24 | 
            +
            		attr :version, true
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            		def initialize(&block)
         | 
| 27 | 
            +
            			@default = {}
         | 
| 28 | 
            +
            			@output = 'build'
         | 
| 29 | 
            +
            			@base = Dir.getwd
         | 
| 30 | 
            +
            			# This should be the last thing to be set up. The object might depend on the other variables.
         | 
| 31 | 
            +
            			@option = PackageOption.new(self, nil, block)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            			self
         | 
| 34 | 
            +
            		end
         | 
| 35 | 
            +
            		
         | 
| 36 | 
            +
            		def output_name
         | 
| 37 | 
            +
            			raise "You can't link packages!"
         | 
| 38 | 
            +
            		end
         | 
| 39 | 
            +
            		
         | 
| 40 | 
            +
            		def name=(name)
         | 
| 41 | 
            +
            			raise "You have already assigned this package a name" if @name
         | 
| 42 | 
            +
            			
         | 
| 43 | 
            +
            			@name = name.to_s
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            			raise PackageError, "The package #{@name} already exist." if Packages[@name]
         | 
| 46 | 
            +
            			Packages[@name] = self
         | 
| 47 | 
            +
            		end
         | 
| 48 | 
            +
            		
         | 
| 49 | 
            +
            		def builder(data = nil)
         | 
| 50 | 
            +
            			builder = Builder.new(self)
         | 
| 51 | 
            +
            			conf = ConfigurationNode.new(@option.package, builder, nil, [])
         | 
| 52 | 
            +
            			@option.apply_config(conf, data)
         | 
| 53 | 
            +
            			builder.conf = conf
         | 
| 54 | 
            +
            			builder
         | 
| 55 | 
            +
            		end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            		def load_config(data)
         | 
| 58 | 
            +
            			conf = PackageConf.new(self)
         | 
| 59 | 
            +
            			Options.new(conf, data, @options)
         | 
| 60 | 
            +
            		end
         | 
| 61 | 
            +
            	end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            	class Library < Package
         | 
| 64 | 
            +
            		def output_name
         | 
| 65 | 
            +
            			if Rake::Win32.windows?
         | 
| 66 | 
            +
            				@name + '.dll'
         | 
| 67 | 
            +
            			else
         | 
| 68 | 
            +
            				@name + '.so'
         | 
| 69 | 
            +
            			end
         | 
| 70 | 
            +
            		end
         | 
| 71 | 
            +
            	end
         | 
| 72 | 
            +
            	
         | 
| 73 | 
            +
            	class Application < Package
         | 
| 74 | 
            +
            		def output_name
         | 
| 75 | 
            +
            			if Platforms.current == Platforms::Windows
         | 
| 76 | 
            +
            				@name + '.exe'
         | 
| 77 | 
            +
            			else
         | 
| 78 | 
            +
            				@name
         | 
| 79 | 
            +
            			end
         | 
| 80 | 
            +
            		end
         | 
| 81 | 
            +
            	end
         | 
| 82 | 
            +
            end
         | 
    
        data/reno/platforms.rb
    ADDED
    
    
    
        data/reno/sourcefile.rb
    ADDED
    
    | @@ -0,0 +1,139 @@ | |
| 1 | 
            +
            require 'digest/md5'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Reno
         | 
| 4 | 
            +
            	class SourceFileError < StandardError
         | 
| 5 | 
            +
            	end
         | 
| 6 | 
            +
            	
         | 
| 7 | 
            +
            	class SourceFile
         | 
| 8 | 
            +
            		attr_reader :path, :name, :row, :db, :builder
         | 
| 9 | 
            +
            		
         | 
| 10 | 
            +
            		def self.locate(builder, filename)
         | 
| 11 | 
            +
            			builder.cache.lock do |cache|
         | 
| 12 | 
            +
            				return cache[filename] || new(builder, filename, cache)
         | 
| 13 | 
            +
            			end
         | 
| 14 | 
            +
            		end
         | 
| 15 | 
            +
            		
         | 
| 16 | 
            +
            		def initialize(builder, filename, cache)
         | 
| 17 | 
            +
            			@builder = builder
         | 
| 18 | 
            +
            			@name = filename
         | 
| 19 | 
            +
            			@path = File.expand_path(@name, @builder.base)
         | 
| 20 | 
            +
            			@changed = Lock.new
         | 
| 21 | 
            +
            			@language = Lock.new
         | 
| 22 | 
            +
            			@lang_conf = Lock.new
         | 
| 23 | 
            +
            			@compiler = Lock.new
         | 
| 24 | 
            +
            			@output = Lock.new
         | 
| 25 | 
            +
            			@content = Lock.new
         | 
| 26 | 
            +
            			@digest = Lock.new
         | 
| 27 | 
            +
            			cache[filename] = self
         | 
| 28 | 
            +
            			@db = @builder.sqlcache.db
         | 
| 29 | 
            +
            			@row = Cache::FileModel.new(@db[:files], @name) do
         | 
| 30 | 
            +
            				{:name => @name, :md5 => digest, :dependencies => false, :output => nil}
         | 
| 31 | 
            +
            			end
         | 
| 32 | 
            +
            		end
         | 
| 33 | 
            +
            		
         | 
| 34 | 
            +
            		def find_language
         | 
| 35 | 
            +
            			file_ext = File.extname(@name).downcase
         | 
| 36 | 
            +
            			
         | 
| 37 | 
            +
            			Languages.constants.map { |name| Languages.const_get(name) }.each do |language|
         | 
| 38 | 
            +
            				next if language.superclass != Languages::Language
         | 
| 39 | 
            +
            				
         | 
| 40 | 
            +
            				if language.extensions.any? { |ext| ext == file_ext }
         | 
| 41 | 
            +
            					return language
         | 
| 42 | 
            +
            				end
         | 
| 43 | 
            +
            			end
         | 
| 44 | 
            +
            			
         | 
| 45 | 
            +
            			raise SourceFileError, "Unable to find a language for the file '#{@name}'."
         | 
| 46 | 
            +
            		end
         | 
| 47 | 
            +
            		
         | 
| 48 | 
            +
            		def digest
         | 
| 49 | 
            +
            			@digest.value {	Digest::MD5.hexdigest(content) }
         | 
| 50 | 
            +
            		end
         | 
| 51 | 
            +
            		
         | 
| 52 | 
            +
            		def content
         | 
| 53 | 
            +
            			@content.value { File.open(@path, 'rb') { |f| f.read } }
         | 
| 54 | 
            +
            		end
         | 
| 55 | 
            +
            		
         | 
| 56 | 
            +
            		def output
         | 
| 57 | 
            +
            			@output.value { @builder.output(@name + '.o') }
         | 
| 58 | 
            +
            		end
         | 
| 59 | 
            +
            		
         | 
| 60 | 
            +
            		def language
         | 
| 61 | 
            +
            			@language.value { find_language }
         | 
| 62 | 
            +
            		end
         | 
| 63 | 
            +
            		
         | 
| 64 | 
            +
            		def compiler
         | 
| 65 | 
            +
            			@compiler.value { Toolchains.locate(language) }
         | 
| 66 | 
            +
            		end
         | 
| 67 | 
            +
            		
         | 
| 68 | 
            +
            		def lang_conf
         | 
| 69 | 
            +
            			@lang_conf.value do
         | 
| 70 | 
            +
            				langs = @builder.conf.get(:langs, nil).map { |langs| langs[language.name] }.reject { |lang| !lang }
         | 
| 71 | 
            +
            				language.merge(langs)
         | 
| 72 | 
            +
            			end
         | 
| 73 | 
            +
            		end
         | 
| 74 | 
            +
            		
         | 
| 75 | 
            +
            		def get_dependencies
         | 
| 76 | 
            +
            			@builder.puts "Getting dependencies for #{@name}..."
         | 
| 77 | 
            +
            			@db[:dependencies].filter(:file => @row[:id]).delete
         | 
| 78 | 
            +
            			
         | 
| 79 | 
            +
            			dependencies = compiler.get_dependencies(self)
         | 
| 80 | 
            +
            			dependencies.each do |path|
         | 
| 81 | 
            +
            				file = SourceFile.locate(@builder, Builder.cleanpath(@builder.base, path))
         | 
| 82 | 
            +
            				@db[:dependencies].insert(:file => @row[:id], :dependency => file.row[:id])
         | 
| 83 | 
            +
            			end
         | 
| 84 | 
            +
            			
         | 
| 85 | 
            +
            			@row[:dependencies] = true
         | 
| 86 | 
            +
            		end
         | 
| 87 | 
            +
            		
         | 
| 88 | 
            +
            		def dependencies_changed?
         | 
| 89 | 
            +
            			get_dependencies unless @row[:dependencies]
         | 
| 90 | 
            +
            			
         | 
| 91 | 
            +
            			dependencies = @db[:dependencies].filter(:file => @row[:id]).all
         | 
| 92 | 
            +
            			
         | 
| 93 | 
            +
            			dependencies.any? do |dependency|
         | 
| 94 | 
            +
            				SourceFile.locate(@builder, @db[:files][:id => dependency[:dependency]][:name]).changed?
         | 
| 95 | 
            +
            			end
         | 
| 96 | 
            +
            		end
         | 
| 97 | 
            +
            		
         | 
| 98 | 
            +
            		def changed?
         | 
| 99 | 
            +
            			@changed.value do |changed|
         | 
| 100 | 
            +
            				# Check if the file has changed and reset dependencies and output if needed
         | 
| 101 | 
            +
            				
         | 
| 102 | 
            +
            				if !File.exists?(@path)
         | 
| 103 | 
            +
            					@row[:dependencies] = false
         | 
| 104 | 
            +
            					changed = true
         | 
| 105 | 
            +
            				elsif @row[:md5] != digest then
         | 
| 106 | 
            +
            					@row[:dependencies] = false
         | 
| 107 | 
            +
            					@row[:md5] = digest
         | 
| 108 | 
            +
            					changed = true
         | 
| 109 | 
            +
            				else
         | 
| 110 | 
            +
            					changed = dependencies_changed? ? true : false
         | 
| 111 | 
            +
            				end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            				@row[:output] = nil if changed
         | 
| 114 | 
            +
            				
         | 
| 115 | 
            +
            				changed
         | 
| 116 | 
            +
            			end
         | 
| 117 | 
            +
            		end
         | 
| 118 | 
            +
            		
         | 
| 119 | 
            +
            		def rebuild?
         | 
| 120 | 
            +
            			return true unless @row[:output] and File.exists?(File.expand_path(@row[:output], @builder.base)) and lang_conf.compare(self)
         | 
| 121 | 
            +
            			
         | 
| 122 | 
            +
            			changed?
         | 
| 123 | 
            +
            		end
         | 
| 124 | 
            +
            		
         | 
| 125 | 
            +
            		def build
         | 
| 126 | 
            +
            			@builder.puts "Compiling #{@name}..."
         | 
| 127 | 
            +
            			compiler.compile(self)
         | 
| 128 | 
            +
            			
         | 
| 129 | 
            +
            			output = @output.value
         | 
| 130 | 
            +
            			
         | 
| 131 | 
            +
            			if File.exists? output
         | 
| 132 | 
            +
            				@row[:output] = output
         | 
| 133 | 
            +
            				lang_conf.store(self)
         | 
| 134 | 
            +
            			else
         | 
| 135 | 
            +
            				raise SourceFileError, "Can't find output '#{output}' from #{name}."
         | 
| 136 | 
            +
            			end
         | 
| 137 | 
            +
            		end
         | 
| 138 | 
            +
            	end
         | 
| 139 | 
            +
            end
         | 
    
        data/reno/toolchains.rb
    ADDED
    
    | @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            module Reno
         | 
| 2 | 
            +
            	module Toolchains
         | 
| 3 | 
            +
            		class ToolchainError < StandardError
         | 
| 4 | 
            +
            		end
         | 
| 5 | 
            +
            		
         | 
| 6 | 
            +
            		Hash = {}
         | 
| 7 | 
            +
            		Compilers = {}
         | 
| 8 | 
            +
            		
         | 
| 9 | 
            +
            		def self.register(toolchain, language)
         | 
| 10 | 
            +
            			array = Compilers[language]
         | 
| 11 | 
            +
            			array = Compilers[language] = [] unless array
         | 
| 12 | 
            +
            			array << toolchain
         | 
| 13 | 
            +
            		end
         | 
| 14 | 
            +
            		
         | 
| 15 | 
            +
            		def self.locate(language)
         | 
| 16 | 
            +
            			array = Compilers[language.name]
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            			raise "Unable to find a compiler for the language '#{language.name}'." unless array
         | 
| 19 | 
            +
            			
         | 
| 20 | 
            +
            			array.first
         | 
| 21 | 
            +
            		end
         | 
| 22 | 
            +
            	
         | 
| 23 | 
            +
            		class Toolchain
         | 
| 24 | 
            +
            			attr_reader :option
         | 
| 25 | 
            +
            			
         | 
| 26 | 
            +
            			def self.get_dependencies(file)
         | 
| 27 | 
            +
            				file.language.get_dependencies(file)
         | 
| 28 | 
            +
            			end
         | 
| 29 | 
            +
            			
         | 
| 30 | 
            +
            			def self.register(name, *languages)
         | 
| 31 | 
            +
            				Hash[name] = self
         | 
| 32 | 
            +
            				
         | 
| 33 | 
            +
            				languages.each do |language|
         | 
| 34 | 
            +
            					Toolchains.register(self, language)
         | 
| 35 | 
            +
            				end
         | 
| 36 | 
            +
            			end
         | 
| 37 | 
            +
            		end
         | 
| 38 | 
            +
            	end
         | 
| 39 | 
            +
            end
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            module Reno
         | 
| 2 | 
            +
            	module Toolchains
         | 
| 3 | 
            +
            		class Gnu < Toolchain
         | 
| 4 | 
            +
            			register :gnu, 'C'
         | 
| 5 | 
            +
            			
         | 
| 6 | 
            +
            			class << self	
         | 
| 7 | 
            +
            				def command(file = nil)
         | 
| 8 | 
            +
            					ENV['CC'] || 'gcc'
         | 
| 9 | 
            +
            				end
         | 
| 10 | 
            +
            				
         | 
| 11 | 
            +
            				def language(file)
         | 
| 12 | 
            +
            					case file.lang_conf
         | 
| 13 | 
            +
            						when Languages::C
         | 
| 14 | 
            +
            							'c'
         | 
| 15 | 
            +
            						else
         | 
| 16 | 
            +
            							raise ToolchainError, "GCC doesn't support the language #{file.language.name}."
         | 
| 17 | 
            +
            					end
         | 
| 18 | 
            +
            				end
         | 
| 19 | 
            +
            				
         | 
| 20 | 
            +
            				def compile(file)
         | 
| 21 | 
            +
            					Builder.execute(command(file), '-pipe', *defines(file), *std(file), '-x', language(file), '-c', file.path, '-o', file.output)
         | 
| 22 | 
            +
            				end
         | 
| 23 | 
            +
            				
         | 
| 24 | 
            +
            				def std(file)
         | 
| 25 | 
            +
            					case file.lang_conf.read(:std)
         | 
| 26 | 
            +
            						when nil
         | 
| 27 | 
            +
            							return []
         | 
| 28 | 
            +
            						when :c89
         | 
| 29 | 
            +
            							result = '89'
         | 
| 30 | 
            +
            						when :c99
         | 
| 31 | 
            +
            							result = '99'
         | 
| 32 | 
            +
            						else
         | 
| 33 | 
            +
            							raise ToolchainError, "Unable to find language mode #{file.lang_conf.read(:std)}."
         | 
| 34 | 
            +
            					end
         | 
| 35 | 
            +
            					
         | 
| 36 | 
            +
            					["-std=#{file.lang_conf.read(:strict) ? "c" : "gnu"}#{result}"]
         | 
| 37 | 
            +
            				end
         | 
| 38 | 
            +
            				
         | 
| 39 | 
            +
            				def defines(file)
         | 
| 40 | 
            +
            					defines = []
         | 
| 41 | 
            +
            					file.lang_conf.read(:defines).each_pair do |key, value|
         | 
| 42 | 
            +
            						defines << '-D' << (value ? "#{key}=#{value}" : key.to_s)
         | 
| 43 | 
            +
            					end
         | 
| 44 | 
            +
            					defines
         | 
| 45 | 
            +
            				end
         | 
| 46 | 
            +
            				
         | 
| 47 | 
            +
            				def link(builder, output)
         | 
| 48 | 
            +
            					Builder.execute(command, '-pipe', *builder.objects.map { |object| object.output }, '-o', output)
         | 
| 49 | 
            +
            				end
         | 
| 50 | 
            +
            			end
         | 
| 51 | 
            +
            		end
         | 
| 52 | 
            +
            	end
         | 
| 53 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,68 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            +
            name: reno
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors: 
         | 
| 7 | 
            +
            - Zoxc
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            date: 2010-02-04 00:00:00 +01:00
         | 
| 13 | 
            +
            default_executable: 
         | 
| 14 | 
            +
            dependencies: []
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            description: 
         | 
| 17 | 
            +
            email: 
         | 
| 18 | 
            +
            executables: []
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            extensions: []
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            extra_rdoc_files: []
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            files: 
         | 
| 25 | 
            +
            - LICENSE
         | 
| 26 | 
            +
            - reno.rb
         | 
| 27 | 
            +
            - reno/builder.rb
         | 
| 28 | 
            +
            - reno/cache.rb
         | 
| 29 | 
            +
            - reno/configuration.rb
         | 
| 30 | 
            +
            - reno/languages/c.rb
         | 
| 31 | 
            +
            - reno/languages.rb
         | 
| 32 | 
            +
            - reno/lock.rb
         | 
| 33 | 
            +
            - reno/options.rb
         | 
| 34 | 
            +
            - reno/package.rb
         | 
| 35 | 
            +
            - reno/platforms.rb
         | 
| 36 | 
            +
            - reno/sourcefile.rb
         | 
| 37 | 
            +
            - reno/toolchains/gnu.rb
         | 
| 38 | 
            +
            - reno/toolchains.rb
         | 
| 39 | 
            +
            has_rdoc: true
         | 
| 40 | 
            +
            homepage: 
         | 
| 41 | 
            +
            licenses: []
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            post_install_message: 
         | 
| 44 | 
            +
            rdoc_options: []
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            require_paths: 
         | 
| 47 | 
            +
            - .
         | 
| 48 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 49 | 
            +
              requirements: 
         | 
| 50 | 
            +
              - - ">="
         | 
| 51 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 52 | 
            +
                  version: 1.9.0
         | 
| 53 | 
            +
              version: 
         | 
| 54 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 55 | 
            +
              requirements: 
         | 
| 56 | 
            +
              - - ">="
         | 
| 57 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 58 | 
            +
                  version: "0"
         | 
| 59 | 
            +
              version: 
         | 
| 60 | 
            +
            requirements: []
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            rubyforge_project: 
         | 
| 63 | 
            +
            rubygems_version: 1.3.5
         | 
| 64 | 
            +
            signing_key: 
         | 
| 65 | 
            +
            specification_version: 3
         | 
| 66 | 
            +
            summary: Reno is a compiling framework in Ruby.
         | 
| 67 | 
            +
            test_files: []
         | 
| 68 | 
            +
             |