execute all build tests in the top-level rake context instead of spawning subprocesses

This commit is contained in:
Josh Holtrop 2013-11-05 16:11:08 -05:00
parent 71344b4782
commit b805e5379f
10 changed files with 135 additions and 112 deletions

View File

@ -1,5 +0,0 @@
Rscons::Environment.new do |env|
env.append('CPPPATH' => Dir['src/**/*/'])
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
env.Program('build_dir', Dir['src/**/*.c'])
end

View File

@ -1,12 +0,0 @@
Rscons::Environment.new do |env|
env.append('CPPPATH' => Dir['src/**/*/'])
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
env.add_tweaker do |build_op|
if build_op[:target] =~ %r{build_one/.*\.o}
build_op[:vars]["CFLAGS"] << "-O1"
elsif build_op[:target] =~ %r{build_two/.*\.o}
build_op[:vars]["CFLAGS"] << "-O2"
end
end
env.Program('tweaker', Dir['src/**/*.c'])
end

View File

@ -1,45 +1,31 @@
require 'fileutils' require 'fileutils'
describe Rscons do describe Rscons do
BUILD_TEST_RUN_DIR = "build_test_run"
before(:all) do before(:all) do
FileUtils.rm_rf('build_tests_run') FileUtils.rm_rf(BUILD_TEST_RUN_DIR)
@owd = Dir.pwd @owd = Dir.pwd
end end
before(:each) do
@output = ""
$stdout.stub(:write) do |content|
@output += content
end
$stderr.stub(:write) do |content|
@output += content
end
end
after(:each) do after(:each) do
Dir.chdir(@owd) Dir.chdir(@owd)
FileUtils.rm_rf('build_tests_run') FileUtils.rm_rf(BUILD_TEST_RUN_DIR)
end end
def build_testdir(build_script = "build.rb") def test_dir(build_test_directory)
if File.exists?(build_script) FileUtils.cp_r("build_tests/#{build_test_directory}", BUILD_TEST_RUN_DIR)
build_rb = File.read(build_script) Dir.chdir(BUILD_TEST_RUN_DIR)
File.open(build_script, "w") do |fh|
fh.puts(<<EOF + build_rb)
require "simplecov"
SimpleCov.start do
root("#{@owd}")
command_name("build_test_#{@build_test_name}")
add_filter("spec")
end
require "rscons"
EOF
end
IO.popen(%{ruby -I #{@owd}/lib #{build_script}}) do |io|
io.readlines.reject do |line|
line =~ /^Coverage report/
end
end.map(&:strip)
end
end
def test_dir(build_test_directory, build_script = "build.rb")
@build_test_name = build_test_directory
FileUtils.cp_r("build_tests/#{build_test_directory}", 'build_tests_run')
Dir.chdir("build_tests_run")
build_testdir(build_script)
end end
def file_sub(fname) def file_sub(fname)
@ -53,18 +39,30 @@ EOF
end end
end end
def lines
@output.lines.map(&:rstrip).tap do |v|
@output = ""
end
end
########################################################################### ###########################################################################
# Tests # Tests
########################################################################### ###########################################################################
it 'builds a C program with one source file' do it 'builds a C program with one source file' do
test_dir('simple') test_dir('simple')
Rscons::Environment.new do |env|
env.Program('simple', Dir['*.c'])
end
File.exists?('simple.o').should be_true File.exists?('simple.o').should be_true
`./simple`.should == "This is a simple C program\n" `./simple`.should == "This is a simple C program\n"
end end
it 'prints commands as they are executed' do it 'prints commands as they are executed' do
lines = test_dir('simple') test_dir('simple')
Rscons::Environment.new do |env|
env.Program('simple', Dir['*.c'])
end
lines.should == [ lines.should == [
'gcc -c -o simple.o -MMD -MF simple.mf simple.c', 'gcc -c -o simple.o -MMD -MF simple.mf simple.c',
'gcc -o simple simple.o', 'gcc -o simple simple.o',
@ -72,7 +70,10 @@ EOF
end end
it 'prints short representations of the commands being executed' do it 'prints short representations of the commands being executed' do
lines = test_dir('header') test_dir('header')
Rscons::Environment.new(echo: :short) do |env|
env.Program('header', Dir['*.c'])
end
lines.should == [ lines.should == [
'CC header.o', 'CC header.o',
'LD header', 'LD header',
@ -81,61 +82,88 @@ EOF
it 'builds a C program with one source file and one header file' do it 'builds a C program with one source file and one header file' do
test_dir('header') test_dir('header')
Rscons::Environment.new(echo: :short) do |env|
env.Program('header', Dir['*.c'])
end
File.exists?('header.o').should be_true File.exists?('header.o').should be_true
`./header`.should == "The value is 2\n" `./header`.should == "The value is 2\n"
end end
it 'rebuilds a C module when a header it depends on changes' do it 'rebuilds a C module when a header it depends on changes' do
test_dir('header') test_dir('header')
env = Rscons::Environment.new(echo: :short) do |env|
env.Program('header', Dir['*.c'])
end
`./header`.should == "The value is 2\n" `./header`.should == "The value is 2\n"
file_sub('header.h') {|line| line.sub(/2/, '5')} file_sub('header.h') {|line| line.sub(/2/, '5')}
build_testdir env.process
`./header`.should == "The value is 5\n" `./header`.should == "The value is 5\n"
end end
it 'does not rebuild a C module when its dependencies have not changed' do it 'does not rebuild a C module when its dependencies have not changed' do
lines = test_dir('header') test_dir('header')
env = Rscons::Environment.new(echo: :short) do |env|
env.Program('header', Dir['*.c'])
end
`./header`.should == "The value is 2\n" `./header`.should == "The value is 2\n"
lines.should == [ lines.should == [
'CC header.o', 'CC header.o',
'LD header', 'LD header',
] ]
lines = build_testdir env.process
lines.should == [] lines.should == []
end end
it "does not rebuild a C module when only the file's timestampe has changed" do it "does not rebuild a C module when only the file's timestampe has changed" do
lines = test_dir('header') test_dir('header')
env = Rscons::Environment.new(echo: :short) do |env|
env.Program('header', Dir['*.c'])
end
`./header`.should == "The value is 2\n" `./header`.should == "The value is 2\n"
lines.should == [ lines.should == [
'CC header.o', 'CC header.o',
'LD header', 'LD header',
] ]
file_sub('header.c') {|line| line} file_sub('header.c') {|line| line}
lines = build_testdir env.process
lines.should == [] lines.should == []
end end
it 're-links a program when the link flags have changed' do it 're-links a program when the link flags have changed' do
lines = test_dir('simple') test_dir('simple')
Rscons::Environment.new do |env|
env.Program('simple', Dir['*.c'])
end
lines.should == [ lines.should == [
'gcc -c -o simple.o -MMD -MF simple.mf simple.c', 'gcc -c -o simple.o -MMD -MF simple.mf simple.c',
'gcc -o simple simple.o', 'gcc -o simple simple.o',
] ]
file_sub('build.rb') {|line| line.sub(/.*CHANGE.FLAGS.*/, ' env["LIBS"] += ["c"]')} Rscons::Environment.new do |env|
lines = build_testdir env["LIBS"] += ["c"]
env.Program('simple', Dir['*.c'])
end
lines.should == ['gcc -o simple simple.o -lc'] lines.should == ['gcc -o simple simple.o -lc']
end end
it 'builds object files in a different build directory' do it 'builds object files in a different build directory' do
lines = test_dir('build_dir') test_dir('build_dir')
Rscons::Environment.new do |env|
env.append('CPPPATH' => Dir['src/**/*/'])
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
env.Program('build_dir', Dir['src/**/*.c'])
end
`./build_dir`.should == "Hello from two()\n" `./build_dir`.should == "Hello from two()\n"
File.exists?('build_one/one.o').should be_true File.exists?('build_one/one.o').should be_true
File.exists?('build_two/two.o').should be_true File.exists?('build_two/two.o').should be_true
end end
it 'cleans built files' do it 'cleans built files' do
lines = test_dir('build_dir') test_dir('build_dir')
Rscons::Environment.new do |env|
env.append('CPPPATH' => Dir['src/**/*/'])
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
env.Program('build_dir', Dir['src/**/*.c'])
end
`./build_dir`.should == "Hello from two()\n" `./build_dir`.should == "Hello from two()\n"
File.exists?('build_one/one.o').should be_true File.exists?('build_one/one.o').should be_true
File.exists?('build_two/two.o').should be_true File.exists?('build_two/two.o').should be_true
@ -148,7 +176,12 @@ EOF
end end
it 'does not clean created directories if other non-rscons-generated files reside there' do it 'does not clean created directories if other non-rscons-generated files reside there' do
lines = test_dir('build_dir') test_dir('build_dir')
Rscons::Environment.new do |env|
env.append('CPPPATH' => Dir['src/**/*/'])
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
env.Program('build_dir', Dir['src/**/*.c'])
end
`./build_dir`.should == "Hello from two()\n" `./build_dir`.should == "Hello from two()\n"
File.exists?('build_one/one.o').should be_true File.exists?('build_one/one.o').should be_true
File.exists?('build_two/two.o').should be_true File.exists?('build_two/two.o').should be_true
@ -162,14 +195,44 @@ EOF
end end
it 'allows Ruby classes as custom builders to be used to construct files' do it 'allows Ruby classes as custom builders to be used to construct files' do
lines = test_dir('custom_builder') test_dir('custom_builder')
class MySource < Rscons::Builder
def run(target, sources, cache, env, vars = {})
File.open(target, 'w') do |fh|
fh.puts <<EOF
#define THE_VALUE 5678
EOF
end
target
end
end
Rscons::Environment.new(echo: :short) do |env|
env.add_builder(MySource.new)
env.MySource('inc.h', [])
env.Program('program', Dir['*.c'])
end
lines.should == ['CC program.o', 'LD program'] lines.should == ['CC program.o', 'LD program']
File.exists?('inc.h').should be_true File.exists?('inc.h').should be_true
`./program`.should == "The value is 5678\n" `./program`.should == "The value is 5678\n"
end end
it 'allows cloning Environment objects' do it 'allows cloning Environment objects' do
lines = test_dir('clone_env') test_dir('clone_env')
debug = Rscons::Environment.new do |env|
env.build_dir('src', 'debug')
env['CFLAGS'] = '-O2'
env['CPPFLAGS'] = '-DSTRING="Debug Version"'
env.Program('program-debug', Dir['src/*.c'])
end
release = debug.clone('CPPFLAGS' => '-DSTRING="Release Version"') do |env|
env.build_dir('src', 'release')
env.Program('program-release', Dir['src/*.c'])
end
lines.should == [ lines.should == [
%q{gcc -c -o debug/program.o -MMD -MF debug/program.mf '-DSTRING="Debug Version"' -O2 src/program.c}, %q{gcc -c -o debug/program.o -MMD -MF debug/program.mf '-DSTRING="Debug Version"' -O2 src/program.c},
%q{gcc -o program-debug debug/program.o}, %q{gcc -o program-debug debug/program.o},
@ -180,12 +243,19 @@ EOF
it 'builds a C++ program with one source file' do it 'builds a C++ program with one source file' do
test_dir('simple_cc') test_dir('simple_cc')
Rscons::Environment.new do |env|
env.Program('simple', Dir['*.cc'])
end
File.exists?('simple.o').should be_true File.exists?('simple.o').should be_true
`./simple`.should == "This is a simple C++ program\n" `./simple`.should == "This is a simple C++ program\n"
end end
it 'allows overriding construction variables for individual builder calls' do it 'allows overriding construction variables for individual builder calls' do
lines = test_dir('two_sources') test_dir('two_sources')
Rscons::Environment.new(echo: :command) do |env|
env.Object("one.o", "one.c", 'CPPFLAGS' => ['-DONE'])
env.Program('two_sources', ['one.o', 'two.c'])
end
lines.should == [ lines.should == [
'gcc -c -o one.o -MMD -MF one.mf -DONE one.c', 'gcc -c -o one.o -MMD -MF one.mf -DONE one.c',
'gcc -c -o two.o -MMD -MF two.mf two.c', 'gcc -c -o two.o -MMD -MF two.mf two.c',
@ -196,7 +266,11 @@ EOF
end end
it 'builds a static library archive' do it 'builds a static library archive' do
lines = test_dir('library') test_dir('library')
Rscons::Environment.new(echo: :command) do |env|
env.Program('library', ['lib.a', 'three.c'])
env.Library("lib.a", ['one.c', 'two.c'], 'CPPFLAGS' => ['-Dmake_lib'])
end
lines.should == [ lines.should == [
'gcc -c -o one.o -MMD -MF one.mf -Dmake_lib one.c', 'gcc -c -o one.o -MMD -MF one.mf -Dmake_lib one.c',
'gcc -c -o two.o -MMD -MF two.mf -Dmake_lib two.c', 'gcc -c -o two.o -MMD -MF two.mf -Dmake_lib two.c',
@ -209,7 +283,19 @@ EOF
end end
it 'supports tweakers to override construction variables' do it 'supports tweakers to override construction variables' do
lines = test_dir("build_dir", "tweaker_build.rb") test_dir("build_dir")
Rscons::Environment.new do |env|
env.append('CPPPATH' => Dir['src/**/*/'])
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
env.add_tweaker do |build_op|
if build_op[:target] =~ %r{build_one/.*\.o}
build_op[:vars]["CFLAGS"] << "-O1"
elsif build_op[:target] =~ %r{build_two/.*\.o}
build_op[:vars]["CFLAGS"] << "-O2"
end
end
env.Program('tweaker', Dir['src/**/*.c'])
end
`./tweaker`.should == "Hello from two()\n" `./tweaker`.should == "Hello from two()\n"
lines.should =~ [ lines.should =~ [
'gcc -c -o build_one/one.o -MMD -MF build_one/one.mf -Isrc/one/ -Isrc/two/ -O1 src/one/one.c', 'gcc -c -o build_one/one.o -MMD -MF build_one/one.mf -Isrc/one/ -Isrc/two/ -O1 src/one/one.c',

View File

@ -1,11 +0,0 @@
debug = Rscons::Environment.new do |env|
env.build_dir('src', 'debug')
env['CFLAGS'] = '-O2'
env['CPPFLAGS'] = '-DSTRING="Debug Version"'
env.Program('program-debug', Dir['src/*.c'])
end
release = debug.clone('CPPFLAGS' => '-DSTRING="Release Version"') do |env|
env.build_dir('src', 'release')
env.Program('program-release', Dir['src/*.c'])
end

View File

@ -1,16 +0,0 @@
class MySource < Rscons::Builder
def run(target, sources, cache, env, vars = {})
File.open(target, 'w') do |fh|
fh.puts <<EOF
#define THE_VALUE 5678
EOF
end
target
end
end
Rscons::Environment.new(echo: :short) do |env|
env.add_builder(MySource.new)
env.MySource('inc.h', [])
env.Program('program', Dir['*.c'])
end

View File

@ -1,3 +0,0 @@
Rscons::Environment.new(echo: :short) do |env|
env.Program('header', Dir['*.c'])
end

View File

@ -1,4 +0,0 @@
Rscons::Environment.new(echo: :command) do |env|
env.Program('library', ['lib.a', 'three.c'])
env.Library("lib.a", ['one.c', 'two.c'], 'CPPFLAGS' => ['-Dmake_lib'])
end

View File

@ -1,4 +0,0 @@
Rscons::Environment.new do |env|
# CHANGE FLAGS
env.Program('simple', Dir['*.c'])
end

View File

@ -1,4 +0,0 @@
Rscons::Environment.new do |env|
# CHANGE FLAGS
env.Program('simple', Dir['*.cc'])
end

View File

@ -1,4 +0,0 @@
Rscons::Environment.new(echo: :command) do |env|
env.Object("one.o", "one.c", 'CPPFLAGS' => ['-DONE'])
env.Program('two_sources', ['one.o', 'two.c'])
end