fill in CC, Program, Environment.process() to get simple builds working

This commit is contained in:
Josh Holtrop 2013-07-07 17:17:46 -04:00
parent 5634b8856d
commit 760f698963
6 changed files with 151 additions and 10 deletions

View File

@ -4,6 +4,7 @@ require "rscons/environment"
require "rscons/version" require "rscons/version"
require "rscons/monkey/module" require "rscons/monkey/module"
require "rscons/monkey/string"
# default builders # default builders
require "rscons/builders/cc" require "rscons/builders/cc"

View File

@ -3,5 +3,8 @@ module Rscons
def initialize(env) def initialize(env)
@env = env @env = env
end end
def default_variables(env)
{}
end
end end
end end

View File

@ -1,4 +1,37 @@
module Rscons module Rscons
class CC < Builder class CC < Builder
def default_variables(env)
{
'CC' => 'gcc',
'CFLAGS' => [],
'CPPFLAGS' => [],
'OBJSUFFIX' => '.o',
'CSUFFIX' => '.c',
'CCDEPGEN' => ['-MMD', '-MF', '$DEPFILE'],
'CCCOM' => ['$CC', '-c', '-o', '$TARGET', '$CCDEPGEN', '$CPPFLAGS', '$CFLAGS', '$SOURCES']
}
end
def produces?(target, source)
target.has_suffix?(@env['OBJSUFFIX']) and source.has_suffix?(@env['CSUFFIX'])
end
def run(target, sources, cache)
unless cache.up_to_date?(target, sources)
vars = {
'TARGET' => target,
'SOURCES' => sources,
'DEPFILE' => target.set_suffix('.mf'),
}
@env.execute("CC #{target}", @env['CCCOM'], vars)
deps = sources
if File.exists?(vars['DEPFILE'])
deps += @env.parse_makefile_deps(vars['DEPFILE'], target)
FileUtils.rm_f(vars['DEPFILE'])
end
cache.register_build(target, deps.uniq)
end
target
end
end end
end end

View File

@ -1,19 +1,38 @@
module Rscons module Rscons
class Program < Builder class Program < Builder
def default_variables def default_variables(env)
{ {
'CC' => 'gcc', 'LD' => nil,
'CFLAGS' => [],
'CPPFLAGS' => [],
'OBJSUFFIX' => '.o', 'OBJSUFFIX' => '.o',
'CSUFFIX' => '.c', 'LIBSUFFIX' => '.a',
'CCDEPGEN' => ['-MMD', '-MF', '$DEPFILE'], 'LDFLAGS' => [],
'CCCOM' => ['$CC', '-c', '-o', '$TARGET', '$CCDEPGEN', '$CPPFLAGS', '$CFLAGS', '$SOURCES'] 'LIBPATHS' => [],
'LIBS' => [],
'LDCOM' => ['$LD', '-o', '$TARGET', '$LDFLAGS', '$SOURCES', '-L$[LIBPATHS]', '-l$[LIBS]']
} }
end end
def produces?(target, source) def run(target, sources, cache)
target.has_suffix?(@env['OBJSUFFIX']) and source.has_suffix?(@env['CSUFFIX']) # convert sources to object file names
sources = sources.map do |source|
if source.has_suffix?([@env['OBJSUFFIX'], @env['LIBSUFFIX']])
source
else
o_file = source.set_suffix(@env['OBJSUFFIX', :string])
builder = @env.builders.values.find { |b| b.produces?(o_file, source) }
builder or raise "No builder found to convert input source #{source.inspect} to an object file."
builder.run(o_file, [source], cache)
end
end
unless cache.up_to_date?(target, sources)
vars = {
'TARGET' => target,
'SOURCES' => sources,
'LD' => @env['LD'] || @env['CC'], # TODO: figure out whether to use CC or CXX
}
@env.execute("LD #{target}", @env['LDCOM'], vars)
end
target
end end
end end
end end

View File

@ -25,6 +25,7 @@ module Rscons
def up_to_date?(file, deps = nil) def up_to_date?(file, deps = nil)
# TODO # TODO
false
end end
def register_build(target, deps) def register_build(target, deps)

View File

@ -1,5 +1,9 @@
require 'set'
module Rscons module Rscons
class Environment class Environment
attr_reader :builders
class << self class << self
alias_method :orig_new, :new alias_method :orig_new, :new
end end
@ -39,6 +43,12 @@ module Rscons
def add_builder(builder) def add_builder(builder)
@builders[builder.class.short_name] = builder @builders[builder.class.short_name] = builder
var_defs = builder.default_variables(self)
if var_defs
var_defs.each_pair do |var, val|
@variables[var] ||= val
end
end
end end
def [](key, type = nil) def [](key, type = nil)
@ -58,15 +68,70 @@ module Rscons
def process def process
cache = Cache.new cache = Cache.new
targets_processed = Set.new
process_target = proc do |target|
sources_built = @targets[target][:source].map do |src|
targets_processed.include?(src) or not @targets.include?(src) or process_target.call(src)
end.all?
if sources_built
@targets[target][:builder].run(target,
@targets[target][:source],
cache,
*@targets[target][:args])
else
false
end
end
@targets.each do |target, info|
next if targets_processed.include?(target)
break unless process_target.call(target)
end
cache.write cache.write
end end
def execute(short_desc, command, extra_vars)
merged_variables = @variables.merge(extra_vars)
expand_varref = proc do |varref|
if varref.is_a?(Array)
varref.map do |ent|
expand_varref.call(ent)
end
else
if varref =~ /^(.*)\$\[(\w+)\](.*)$/
# expand array with given prefix, suffix
prefix, varname, suffix = $1, $2, $3
varval = merged_variables[varname]
unless varval.is_a?(Array)
raise "Array expected for $#{varname}"
end
varval.map {|e| "#{prefix}#{e}#{suffix}"}
elsif varref =~ /^\$(.*)$/
# expand a single variable reference
varname = $1
varval = merged_variables[varname]
varval or raise "Could not find variable #{varname.inspect}"
expand_varref.call(varval)
else
varref
end
end
end
command = expand_varref.call(command.flatten).flatten
if @echo == :command
puts command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ')
elsif @echo == :short
puts short_desc
end
system(*command)
end
alias_method :orig_method_missing, :method_missing alias_method :orig_method_missing, :method_missing
def method_missing(method, *args) def method_missing(method, *args)
if @builders.has_key?(method.to_s) if @builders.has_key?(method.to_s)
target, source, *rest = args target, source, *rest = args
source = [source] unless source.is_a?(Array)
@targets[target] = { @targets[target] = {
builder: method.to_s, builder: @builders[method.to_s],
source: source, source: source,
args: rest, args: rest,
} }
@ -74,5 +139,24 @@ module Rscons
orig_method_missing(method, *args) orig_method_missing(method, *args)
end end
end end
def parse_makefile_deps(mf_fname, target)
deps = []
buildup = ''
File.read(mf_fname).each_line do |line|
if line =~ /^(.*)\\\s*$/
buildup += ' ' + $1
else
if line =~ /^(.*): (.*)$/
target, tdeps = $1.strip, $2
if target == target
deps += tdeps.split(' ').map(&:strip)
end
end
buildup = ''
end
end
deps
end
end end
end end