Compare commits

...
11 Commits
Author SHA1 Message Date
josh 86fcebbda7 wip for precompile phase for D 2026-01-18 21:23:50 -05:00
josh 67c135f610 wip 2026-01-18 11:14:29 -05:00
josh 94a86e3433 Add Barrier builder 2026-01-16 22:54:22 -05:00
josh fc18c9f123 Test phony dependencies 2026-01-16 20:21:13 -05:00
josh 1d020d1aef Update gems 2026-01-15 21:07:18 -05:00
josh 19c5c8cfba Update gems 2025-11-22 00:14:26 -05:00
josh 4fc7ab6b25 v3.3.0 2025-06-10 20:14:15 -04:00
josh 161da80ffe Update CHANGELOG for v3.3.0 2025-06-10 20:13:37 -04:00
josh 8d9f19cb34 Add github workflow to run RScons tests
Fix up some macOS test cases
2025-06-08 20:46:09 -04:00
josh 18a2a075c1 Remove dependency on base64 - close #177 2025-06-08 02:48:03 -04:00
josh 1a280a8994 Update gems 2025-06-07 20:30:48 -04:00
27 changed files with 472 additions and 120 deletions

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
name: Run RScons Tests
on:
push:
branches:
- master
pull_request:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
ruby-version: ['2.7', '3.0', '3.4']
steps:
- name: Install dependencies (Linux)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y gcc gdc ldc clang flex bison
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: brew install gcc ldc flex bison
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
- name: Install dependencies
run: bundle install
- name: Run tests
run: rake all
+9
View File
@@ -1,3 +1,12 @@
## v3.3.0
### New Features
- Add support for Ruby 3.4.
- Fix up some macOS test cases.
- #177 - Remove dependency on base64
- #175 - Add support for building object files from LLVM assembly sources
## v3.2.0 ## v3.2.0
### New Features ### New Features
+1
View File
@@ -4,6 +4,7 @@ gem "base64"
gem "rspec" gem "rspec"
gem "rake" gem "rake"
gem "simplecov", "~> 0.15.0" gem "simplecov", "~> 0.15.0"
gem "openssl"
if RbConfig::CONFIG["host"]["msys"] if RbConfig::CONFIG["host"]["msys"]
gem "json", "2.1.0" gem "json", "2.1.0"
else else
+21 -15
View File
@@ -1,39 +1,44 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
base64 (0.2.0) base64 (0.3.0)
date (3.4.1) date (3.5.1)
diff-lcs (1.6.0) diff-lcs (1.6.2)
docile (1.1.5) docile (1.1.5)
json (2.10.2) erb (6.0.1)
psych (5.2.3) json (2.18.0)
openssl (4.0.0)
psych (5.3.1)
date date
stringio stringio
rake (13.2.1) rake (13.3.1)
rdoc (6.13.0) rdoc (7.1.0)
erb
psych (>= 4.0.0) psych (>= 4.0.0)
tsort
redcarpet (3.6.1) redcarpet (3.6.1)
rspec (3.13.0) rspec (3.13.2)
rspec-core (~> 3.13.0) rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0) rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0) rspec-mocks (~> 3.13.0)
rspec-core (3.13.3) rspec-core (3.13.6)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-expectations (3.13.3) rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-mocks (3.13.2) rspec-mocks (3.13.7)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-support (3.13.2) rspec-support (3.13.6)
simplecov (0.15.1) simplecov (0.15.1)
docile (~> 1.1.0) docile (~> 1.1.0)
json (>= 1.8, < 3) json (>= 1.8, < 3)
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.2) simplecov-html (0.10.2)
stringio (3.1.5) stringio (3.2.0)
syntax (1.2.2) syntax (1.2.2)
yard (0.9.37) tsort (0.2.0)
yard (0.9.38)
PLATFORMS PLATFORMS
ruby ruby
@@ -42,6 +47,7 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
base64 base64
json json
openssl
rake rake
rdoc rdoc
redcarpet redcarpet
@@ -51,4 +57,4 @@ DEPENDENCIES
yard yard
BUNDLED WITH BUNDLED WITH
2.4.17 2.6.2
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2013-2022 Josh Holtrop Copyright (c) 2013-2025 Josh Holtrop
MIT License MIT License
+3 -2
View File
@@ -32,11 +32,12 @@ end
# useful for coverage information. # useful for coverage information.
desc "Dist Specs" desc "Dist Specs"
task :dspec, [:example_string] => :build_dist do |task, args| task :dspec, [:example_string] => :build_dist do |task, args|
FileUtils.rm_rf("test")
FileUtils.mkdir_p("test") FileUtils.mkdir_p("test")
FileUtils.cp("dist/rscons", "test/rscons.rb") FileUtils.cp("dist/rscons", "test/rscons.rb")
ENV["dist_specs"] = "1" ENV["rscons_dist_specs"] = "1"
Rake::Task["spec"].execute(args) Rake::Task["spec"].execute(args)
ENV.delete("dist_specs") ENV.delete("rscons_dist_specs")
FileUtils.rm_f(Dir.glob(".rscons-*")) FileUtils.rm_f(Dir.glob(".rscons-*"))
end end
+2 -1
View File
@@ -3,5 +3,6 @@ configure do
end end
env(echo: :command) do |env| env(echo: :command) do |env|
env.Program("hello-d.exe", glob("*.d")) env["D_IMPORT_PATH"] << "src"
env.Program("hello-d.exe", glob("src/*.d"))
end end
+2 -1
View File
@@ -3,5 +3,6 @@ configure do
end end
env(echo: :command) do |env| env(echo: :command) do |env|
env.Program("hello-d.exe", glob("*.d")) env["D_IMPORT_PATH"] << "src"
env.Program("hello-d.exe", glob("src/*.d"))
end end
+3 -2
View File
@@ -1,5 +1,6 @@
env(echo: :command) do |env| env(echo: :command) do |env|
env.Object("main.o", "main.d") env["LD_LIBRARY_PATH"] << "src"
env.Object("mod.o", "mod.d") env.Object("main.o", "src/main.d")
env.Object("mod.o", "src/mod.d")
env.Program("hello-d.exe", ["main.o", "mod.o"]) env.Program("hello-d.exe", ["main.o", "mod.o"])
end end
File renamed without changes.
File renamed without changes.
+1 -1
View File
@@ -3,5 +3,5 @@ env do |env|
env["CFLAGS"] += %w[-S] env["CFLAGS"] += %w[-S]
env.Object("one.ssss", "one.c", "CPPFLAGS" => ["-DONE"]) env.Object("one.ssss", "one.c", "CPPFLAGS" => ["-DONE"])
env.Object("two.sss", "two.c") env.Object("two.sss", "two.c")
env.Program("two_sources.exe", %w[one.ssss two.sss], "ASFLAGS" => env["ASFLAGS"] + %w[-x assembler]) env.Program("two_sources.exe", %w[one.ssss two.sss], "ASFLAGS" => env["ASFLAGS"] + %w[-x assembler-with-cpp])
end end
+15
View File
@@ -0,0 +1,15 @@
class Custom < Rscons::Builder
def run(options)
print_run_message("#{name} #{target}", nil)
true
end
end
env do |env|
env.add_builder(Custom)
env.Custom("t3", :phony1)
env.Custom(:phony1, "t2")
env.Custom("t2", :phony2)
env.Custom(:phony2, "t1")
env.Custom("t1", [])
end
+11
View File
@@ -23,6 +23,7 @@ module Rscons
# Names of the default builders which will be added to all newly created # Names of the default builders which will be added to all newly created
# {Environment} objects. # {Environment} objects.
DEFAULT_BUILDERS = [ DEFAULT_BUILDERS = [
:Barrier,
:Command, :Command,
:Copy, :Copy,
:Directory, :Directory,
@@ -32,6 +33,7 @@ module Rscons
:Lex, :Lex,
:Library, :Library,
:Object, :Object,
:Precompile,
:Preprocess, :Preprocess,
:Program, :Program,
:SharedLibrary, :SharedLibrary,
@@ -66,6 +68,13 @@ module Rscons
target.is_a?(Symbol) target.is_a?(Symbol)
end end
# Generate a random phony target name.
#
# @return [Symbol] Phony target name.
def gen_phony_target
("t" + sprintf("%08x", rand(1_000_000..4_000_000_000))).to_sym
end
# Return the system shell and arguments for executing a shell command. # Return the system shell and arguments for executing a shell command.
# #
# @return [Array<String>] The shell and flag. # @return [Array<String>] The shell and flag.
@@ -136,6 +145,7 @@ require_relative "rscons/builders/mixins/object_deps"
require_relative "rscons/builders/mixins/program" require_relative "rscons/builders/mixins/program"
# default builders # default builders
require_relative "rscons/builders/barrier"
require_relative "rscons/builders/command" require_relative "rscons/builders/command"
require_relative "rscons/builders/copy" require_relative "rscons/builders/copy"
require_relative "rscons/builders/directory" require_relative "rscons/builders/directory"
@@ -143,6 +153,7 @@ require_relative "rscons/builders/disassemble"
require_relative "rscons/builders/lex" require_relative "rscons/builders/lex"
require_relative "rscons/builders/library" require_relative "rscons/builders/library"
require_relative "rscons/builders/object" require_relative "rscons/builders/object"
require_relative "rscons/builders/precompile"
require_relative "rscons/builders/preprocess" require_relative "rscons/builders/preprocess"
require_relative "rscons/builders/program" require_relative "rscons/builders/program"
require_relative "rscons/builders/shared_library" require_relative "rscons/builders/shared_library"
+10 -3
View File
@@ -27,8 +27,9 @@ module Rscons
# env.Directory("dest") # env.Directory("dest")
# env.Install("dest", "bin") # env.Install("dest", "bin")
# env.Install("dest", "share") # env.Install("dest", "share")
self[builder.target] ||= [] target = Util.absolute_path(builder.target)
self[builder.target] << builder self[target] ||= []
self[target] << builder
end end
# Return the number of remaining build steps. # Return the number of remaining build steps.
@@ -37,7 +38,7 @@ module Rscons
# The number of remaining build steps. # The number of remaining build steps.
def build_steps_remaining def build_steps_remaining
self.reduce(0) do |result, (target, builders)| self.reduce(0) do |result, (target, builders)|
result + builders.size result + builders.count {|b| !b.is_a?(Rscons::Builders::Barrier)}
end end
end end
@@ -55,9 +56,14 @@ module Rscons
def get_next_builder_to_run(targets_still_building) def get_next_builder_to_run(targets_still_building)
to_build = self.find do |target, builders| to_build = self.find do |target, builders|
deps = builders.first.sources + (@build_dependencies[target] || []).to_a deps = builders.first.sources + (@build_dependencies[target] || []).to_a
deps.map! {|dep| Util.absolute_path(dep)}
# All dependencies must have been built for this target to be ready to # All dependencies must have been built for this target to be ready to
# build. # build.
deps.all? do |dep| deps.all? do |dep|
puts "BuilderSet: #{target}: dep #{dep}"
puts " still building? #{targets_still_building.include?(dep)}"
puts " self.include? #{self.include?(dep)}"
puts " @side_effects.include? #{@side_effects.include?(dep)}"
!(targets_still_building.include?(dep) || !(targets_still_building.include?(dep) ||
self.include?(dep) || self.include?(dep) ||
@side_effects.include?(dep)) @side_effects.include?(dep))
@@ -66,6 +72,7 @@ module Rscons
if to_build if to_build
target, builders = *to_build target, builders = *to_build
puts "Selecting #{target.inspect} to build"
builder = builders.first builder = builders.first
if builders.size > 1 if builders.size > 1
builders.slice!(0) builders.slice!(0)
+15
View File
@@ -0,0 +1,15 @@
module Rscons
module Builders
# The Barrier builder does not perform any action. It exists as a builder
# on which to place dependencies to ensure that each of its sources are
# built before any build targets which depend on the barrier build target.
class Barrier < Builder
# Run the builder.
def run(options)
true
end
end
end
end
+6 -1
View File
@@ -15,11 +15,16 @@ module Rscons
# List of paths to the object or static library dependencies. # List of paths to the object or static library dependencies.
def register_object_deps(builder_class) def register_object_deps(builder_class)
suffixes = @env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], @vars) suffixes = @env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], @vars)
barrier_target = @env.setup_precompile(@sources)
@sources.map do |source| @sources.map do |source|
if source.end_with?(*suffixes) if source.end_with?(*suffixes)
source source
else else
@env.register_dependency_build(@target, source, suffixes.first, @vars, builder_class) object_file_path = @env.register_dependency_build(@target, source, suffixes.first, @vars, builder_class)
if barrier_target
@env.depends(object_file_path, barrier_target)
end
object_file_path
end end
end end
end end
+29
View File
@@ -0,0 +1,29 @@
module Rscons
module Builders
# The Precompile builder generates .di interface files from .d source files
# for D.
class Precompile < Builder
# Run the builder to produce a build target.
def run(options)
if @command
finalize_command
else
if @sources.find {|s| s.end_with?(*@env.expand_varref("${DSUFFIX}", @vars))}
pcc = @env.expand_varref("${DC}")
if pcc =~ /ldc/
dpc_cmd = "${DPC_CMD:ldc}"
else
dpc_cmd = "${DPC_CMD:gdc}"
end
@vars["_TARGET"] = @target
@vars["_SOURCES"] = @sources
command = @env.build_command(dpc_cmd, @vars)
standard_command("Precompile <source>#{Util.short_format_paths(@sources)}<reset>", command)
end
end
end
end
end
end
+31 -17
View File
@@ -142,14 +142,16 @@ module Rscons
# - each cached dependency file's current checksum matches the checksum # - each cached dependency file's current checksum matches the checksum
# stored in the cache file # stored in the cache file
def up_to_date?(targets, command, deps, env, options = {}) def up_to_date?(targets, command, deps, env, options = {})
deps.map! {|dep| Util.absolute_path(dep)}
Array(targets).each do |target| Array(targets).each do |target|
target = Util.absolute_path(target)
cache_key = get_cache_key(target) cache_key = get_cache_key(target)
unless Rscons.phony_target?(target) unless Rscons.phony_target?(target)
# target file must exist on disk # target file must exist on disk
unless File.exist?(target) unless File.exist?(target)
if options[:debug] if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Target #{target} needs rebuilding because it does not exist on disk" puts "Cache: up_to_date?: Target #{target} needs rebuilding because it does not exist on disk"
end end
return false return false
end end
@@ -157,8 +159,8 @@ module Rscons
# target must be registered in the cache # target must be registered in the cache
unless @cache["targets"].has_key?(cache_key) unless @cache["targets"].has_key?(cache_key)
if options[:debug] if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Target #{target} needs rebuilding because there is no cached build information for it" puts "Cache: up_to_date?: Target #{target} needs rebuilding because there is no cached build information for it"
end end
return false return false
end end
@@ -166,8 +168,8 @@ module Rscons
unless Rscons.phony_target?(target) unless Rscons.phony_target?(target)
# target must have the same checksum as when it was built last # target must have the same checksum as when it was built last
unless @cache["targets"][cache_key]["checksum"] == lookup_checksum(target) unless @cache["targets"][cache_key]["checksum"] == lookup_checksum(target)
if options[:debug] if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Target #{target} needs rebuilding because it has been changed on disk since being built last" puts "Cache: up_to_date?: Target #{target} needs rebuilding because it has been changed on disk since being built last"
end end
return false return false
end end
@@ -175,8 +177,8 @@ module Rscons
# command used to build target must be identical # command used to build target must be identical
unless @cache["targets"][cache_key]["command"] == Digest::MD5.hexdigest(command.inspect) unless @cache["targets"][cache_key]["command"] == Digest::MD5.hexdigest(command.inspect)
if options[:debug] if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Target #{target} needs rebuilding because the command used to build it has changed" puts "Cache: up_to_date?: Target #{target} needs rebuilding because the command used to build it has changed"
end end
return false return false
end end
@@ -186,16 +188,16 @@ module Rscons
if options[:strict_deps] if options[:strict_deps]
# depedencies passed in must exactly equal those in the cache # depedencies passed in must exactly equal those in the cache
unless deps == cached_deps_fnames unless deps == cached_deps_fnames
if options[:debug] if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Target #{target} needs rebuilding because the :strict_deps option is given and the set of dependencies does not match the previous set of dependencies" puts "Cache: up_to_date?: Target #{target} needs rebuilding because the :strict_deps option is given and the set of dependencies does not match the previous set of dependencies"
end end
return false return false
end end
else else
# all dependencies passed in must exist in cache (but cache may have more) # all dependencies passed in must exist in cache (but cache may have more)
unless (Set.new(deps) - Set.new(cached_deps_fnames)).empty? unless (Set.new(deps) - Set.new(cached_deps_fnames)).empty?
if options[:debug] if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Target #{target} needs rebuilding because there are new dependencies" puts "Cache: up_to_date?: Target #{target} needs rebuilding because there are new dependencies"
end end
return false return false
end end
@@ -203,11 +205,12 @@ module Rscons
# set of user dependencies must match # set of user dependencies must match
user_deps = env.get_user_deps(target) || [] user_deps = env.get_user_deps(target) || []
user_deps.map! {|dep| Util.absolute_path(dep)}
cached_user_deps = @cache["targets"][cache_key]["user_deps"] || [] cached_user_deps = @cache["targets"][cache_key]["user_deps"] || []
cached_user_deps_fnames = cached_user_deps.map { |dc| dc["fname"] } cached_user_deps_fnames = cached_user_deps.map { |dc| dc["fname"] }
unless user_deps == cached_user_deps_fnames unless user_deps == cached_user_deps_fnames
if options[:debug] if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Target #{target} needs rebuilding because the set of user-specified dependency files has changed" puts "Cache: up_to_date?: Target #{target} needs rebuilding because the set of user-specified dependency files has changed"
end end
return false return false
end end
@@ -215,12 +218,14 @@ module Rscons
# all cached dependencies must have their checksums match # all cached dependencies must have their checksums match
(cached_deps + cached_user_deps).each do |dep_cache| (cached_deps + cached_user_deps).each do |dep_cache|
unless dep_cache["checksum"] == lookup_checksum(dep_cache["fname"]) unless dep_cache["checksum"] == lookup_checksum(dep_cache["fname"])
if options[:debug] if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Target #{target} needs rebuilding because dependency file #{dep_cache["fname"]} has changed" puts "Cache: up_to_date?: Target #{target} needs rebuilding because dependency file #{dep_cache["fname"]} has changed"
end end
return false return false
end end
end end
puts "Cache: up_to_date?: Target #{target} is up to date" if ENV["RSCONS_CACHE_DEBUG"]
end end
true true
@@ -247,22 +252,26 @@ module Rscons
# @return [void] # @return [void]
def register_build(targets, command, deps, env, options = {}) def register_build(targets, command, deps, env, options = {})
Array(targets).each do |target| Array(targets).each do |target|
target = Util.absolute_path(target)
target_checksum = target_checksum =
if options[:side_effect] or Rscons.phony_target?(target) if options[:side_effect] or Rscons.phony_target?(target)
"" ""
else else
calculate_checksum(target) calculate_checksum(target)
end end
puts "Cache: register_build(#{target}, #{target_checksum})"
@cache["targets"][get_cache_key(target)] = { @cache["targets"][get_cache_key(target)] = {
"command" => Digest::MD5.hexdigest(command.inspect), "command" => Digest::MD5.hexdigest(command.inspect),
"checksum" => target_checksum, "checksum" => target_checksum,
"deps" => deps.map do |dep| "deps" => deps.map do |dep|
dep = Util.absolute_path(dep)
{ {
"fname" => dep, "fname" => dep,
"checksum" => lookup_checksum(dep), "checksum" => lookup_checksum(dep),
} }
end, end,
"user_deps" => (env.get_user_deps(target) || []).map do |dep| "user_deps" => (env.get_user_deps(target) || []).map do |dep|
dep = Util.absolute_path(dep)
{ {
"fname" => dep, "fname" => dep,
"checksum" => lookup_checksum(dep), "checksum" => lookup_checksum(dep),
@@ -381,6 +390,8 @@ module Rscons
# #
# @return [String] The file's checksum. # @return [String] The file's checksum.
def lookup_checksum(file) def lookup_checksum(file)
file = Util.absolute_path(file)
puts "Cache: lookup_checksum(#{file})" if ENV["RSCONS_CACHE_DEBUG"]
@lookup_checksums[file] || calculate_checksum(file) @lookup_checksums[file] || calculate_checksum(file)
end end
@@ -390,7 +401,10 @@ module Rscons
# #
# @return [String] The file's checksum. # @return [String] The file's checksum.
def calculate_checksum(file) def calculate_checksum(file)
@lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file, mode: "rb")) rescue "" file = Util.absolute_path(file)
cs = Digest::MD5.hexdigest(File.read(file, mode: "rb")) rescue ""
puts "Cache: calculate_checksum(#{file}) = #{cs}" if ENV["RSCONS_CACHE_DEBUG"]
@lookup_checksums[file] = cs
end end
end end
@@ -43,6 +43,8 @@ module Rscons
"DFLAGS" => [], "DFLAGS" => [],
"DISASM_CMD" => %w[${OBJDUMP} ${DISASM_FLAGS} ${_SOURCES}], "DISASM_CMD" => %w[${OBJDUMP} ${DISASM_FLAGS} ${_SOURCES}],
"DISASM_FLAGS" => %w[--disassemble --source], "DISASM_FLAGS" => %w[--disassemble --source],
"DPC_CMD:ldc" => %w[${DC} -H -Hf ${_TARGET} -o- ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${_SOURCES}],
"DPC_CMD:gdc" => %w[${DC} -H -Hf ${_TARGET} -fsyntax-only ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${_SOURCES}],
"DSUFFIX" => %w[.d], "DSUFFIX" => %w[.d],
"D_IMPORT_PATH" => [], "D_IMPORT_PATH" => [],
"INCPREFIX" => "-I", "INCPREFIX" => "-I",
+72 -11
View File
@@ -291,6 +291,17 @@ module Rscons
end end
end end
# Get a path under the build root for precompile outputs.
#
# @param end_path [String]
# Path to append to precompile build root.
#
# @return [String]
# Precompile directory name.
def get_pc_build_dir(end_path)
"#{@build_root}/pc/#{Util.make_relative_path(end_path)}"
end
# Build all build targets specified in the Environment. # Build all build targets specified in the Environment.
# #
# When a block is passed to Environment.new, this method is automatically # When a block is passed to Environment.new, this method is automatically
@@ -389,7 +400,9 @@ module Rscons
if target.is_a?(Builder) if target.is_a?(Builder)
target = target.target target = target.target
end end
target = expand(target.to_s) unless Rscons.phony_target?(target)
target = Util.absolute_path(expand(target))
end
user_deps = user_deps.map do |ud| user_deps = user_deps.map do |ud|
if ud.is_a?(Builder) if ud.is_a?(Builder)
ud = ud.target ud = ud.target
@@ -397,7 +410,11 @@ module Rscons
expand(ud) expand(ud)
end end
@user_deps[target] ||= [] @user_deps[target] ||= []
@user_deps[target] = (@user_deps[target] + user_deps).uniq user_deps.each do |ud|
unless @user_deps[target].include?(ud)
@user_deps[target] << Util.absolute_path(ud)
end
end
build_after(target, user_deps) build_after(target, user_deps)
end end
@@ -428,14 +445,16 @@ module Rscons
targets = Array(targets) targets = Array(targets)
prerequisites = Array(prerequisites) prerequisites = Array(prerequisites)
targets.each do |target| targets.each do |target|
target = expand(target) unless Rscons.phony_target?(target)
target = Util.absolute_path(expand(target))
end
@registered_build_dependencies[target] ||= Set.new @registered_build_dependencies[target] ||= Set.new
prerequisites.each do |prerequisite| prerequisites.each do |prerequisite|
if prerequisite.is_a?(Builder) if prerequisite.is_a?(Builder)
prerequisite = prerequisite.target prerequisite = prerequisite.target
end end
prerequisite = expand(prerequisite) prerequisite = expand(prerequisite)
@registered_build_dependencies[target] << prerequisite @registered_build_dependencies[target] << Util.absolute_path(prerequisite)
end end
end end
end end
@@ -450,7 +469,7 @@ module Rscons
# #
# @return [void] # @return [void]
def produces(target, *side_effects) def produces(target, *side_effects)
target = expand(target) target = Util.absolute_path(expand(target))
@builder_sets.reverse.each do |builder_set| @builder_sets.reverse.each do |builder_set|
if builders = builder_set[target] if builders = builder_set[target]
builders.last.produces(*side_effects) builders.last.produces(*side_effects)
@@ -596,6 +615,42 @@ module Rscons
@builder_sets << build_builder_set @builder_sets << build_builder_set
end end
# Set up builders and barrier for a precompile phase if needed.
#
# @param sources [Array<String>]
# Sources for the build operation.
#
# @return [Symbol, nil]
# Barrier target name if a precompile phase is needed, otherwise nil.
def setup_precompile(sources)
barrier_target = nil
precompile_paths = Set.new
sources.each do |source|
next unless source.end_with?(".d")
unless barrier_target
barrier_target = Rscons.gen_phony_target
self.Barrier(barrier_target)
end
next unless module_name = Util.get_module_name(source)
next unless import_path = Util.find_import_path_for_d_source(self["D_IMPORT_PATH"], source, module_name)
precompile_path = get_pc_build_dir(import_path)
unless precompile_paths.include?(precompile_path)
Util.clean_d_precompile_path(precompile_path, import_path)
precompile_paths << precompile_path
end
unless self["D_IMPORT_PATH"].include?(precompile_path)
# Put the precompile path containing the .di files for the given
# import path immediately before the import path.
index = self["D_IMPORT_PATH"].find_index {|ip| ip == import_path}
self["D_IMPORT_PATH"].insert(index, precompile_path)
end
pctarget = "#{precompile_path}/#{module_name.gsub(".", "/")}.di"
self.Precompile(pctarget, source)
self.depends(barrier_target, pctarget)
end
barrier_target
end
private private
# Build a BuilderSet. # Build a BuilderSet.
@@ -623,7 +678,9 @@ module Rscons
# #
# @return [void] # @return [void]
def run_builder(builder) def run_builder(builder)
builder.build_step ||= get_next_build_step unless builder.is_a?(Rscons::Builders::Barrier)
builder.build_step ||= get_next_build_step
end
case result = builder.run({}) case result = builder.run({})
when Array when Array
result.each do |waititem| result.each do |waititem|
@@ -649,8 +706,10 @@ module Rscons
Cache.instance.register_build(side_effect, nil, [], self, side_effect: true) Cache.instance.register_build(side_effect, nil, [], self, side_effect: true)
@side_effects.delete(side_effect) @side_effects.delete(side_effect)
end end
@build_hooks[:post].each do |build_hook_block| unless builder.is_a?(Rscons::Builders::Barrier)
build_hook_block.call(builder) @build_hooks[:post].each do |build_hook_block|
build_hook_block.call(builder)
end
end end
process_remove_wait(builder) process_remove_wait(builder)
else else
@@ -722,13 +781,15 @@ module Rscons
# If no builder was found to run yet and there are threads available, try # If no builder was found to run yet and there are threads available, try
# to get a runnable builder from the builder set. # to get a runnable builder from the builder set.
targets_still_building = @threads.reduce([]) do |result, (thread, obj)| targets_still_building = @threads.reduce([]) do |result, (thread, obj)|
result << builder_for_thread(thread).target result << Util.absolute_path(builder_for_thread(thread).target)
end end
if @builder_sets.size > 0 if @builder_sets.size > 0
if builder = @builder_sets[0].get_next_builder_to_run(targets_still_building) if builder = @builder_sets[0].get_next_builder_to_run(targets_still_building)
builder.vars = @varset.merge(builder.vars) builder.vars = @varset.merge(builder.vars)
@build_hooks[:pre].each do |build_hook_block| unless builder.is_a?(Rscons::Builders::Barrier)
build_hook_block.call(builder) @build_hooks[:pre].each do |build_hook_block|
build_hook_block.call(builder)
end
end end
return run_builder(builder) return run_builder(builder)
end end
+1 -9
View File
@@ -34,15 +34,7 @@ module Rscons
# #
# @return [Array<String>] Paths matching the specified pattern(s). # @return [Array<String>] Paths matching the specified pattern(s).
def glob(*patterns) def glob(*patterns)
require "pathname" Util.glob(*patterns)
patterns.reduce([]) do |result, pattern|
if pattern.end_with?("/**")
pattern += "/"
end
result += Dir.glob(pattern).map do |path|
Pathname.new(path.gsub("\\", "/")).cleanpath.to_s
end
end.sort
end end
# Download a file. # Download a file.
+105
View File
@@ -16,6 +16,42 @@ module Rscons
end end
end end
# Get the absolute path for a given path.
#
# If the path is a phony target, leave it as is.
#
# @param path [String, Symbol]
# Input path.
#
# @return [String, Symbol]
# Output path.
def absolute_path(path)
if Rscons.phony_target?(path)
path
else
File.expand_path(path)
end
end
# Remove any stale .di files from the precompile path.
#
# @param pc_path [String]
# Path to precompile build directory containing .di generated
# interface files.
# @param import_path [String]
# D import path containing .d source files.
#
# @return [void]
def clean_d_precompile_path(pc_path, import_path)
glob("#{pc_path}/**/*.di").each do |di_path|
end_path = di_path[(pc_path.size+1)..]
path = "#{import_path}/#{end_path}".sub(/\.di$/, ".d")
unless File.exist?(path)
FileUtils.rm_f(path)
end
end
end
# Colorize a builder run message. # Colorize a builder run message.
# #
# @param message [String] # @param message [String]
@@ -120,6 +156,29 @@ module Rscons
end end
end end
# Find the D import path that will be used to import the given module.
#
# @param import_paths [Array<String>]
# Import paths.
# @param source [String]
# Source file name.
# @param module_name [String]
# Module name.
#
# @return [String, nil]
# Import path used to import the given module.
def find_import_path_for_d_source(import_paths, source, module_name)
source = source.gsub("\\", "/")
module_path = module_name.gsub(".", "/") + ".d"
import_paths.each do |import_path|
path = "#{import_path}/#{module_path}".gsub("\\", "/")
if path == source
return import_path
end
end
nil
end
# Format an elapsed time in human-readable format. # Format an elapsed time in human-readable format.
# #
# @return [String] # @return [String]
@@ -141,6 +200,52 @@ module Rscons
result result
end end
# Get the module name for a D source file.
#
# @param source_path [String]
# D source file.
#
# @return [String, nil]
# Module name.
def get_module_name(source_path)
if File.exist?(source_path)
if File.binread(source_path) =~ /^\s*module\s(\S*);/
return $1
end
name = File.basename(source_path).sub(/\.d$/, "")
if name =~ /^\w+$/
return name
end
end
end
# Return a list of paths matching the specified pattern(s).
#
# A pattern can contain a "/**" component to recurse through directories.
# If the pattern ends with "/**" then only the recursive list of
# directories will be returned.
#
# Examples:
# - "src/**": return all directories under "src", recursively (including
# "src" itself).
# - "src/**/*": return all files and directories recursively under the src
# directory.
# - "src/**/*.c": return all .c files recursively under the src directory.
# - "dir/*/": return all directories in dir, but no files.
#
# @return [Array<String>] Paths matching the specified pattern(s).
def glob(*patterns)
require "pathname"
patterns.reduce([]) do |result, pattern|
if pattern.end_with?("/**")
pattern += "/"
end
result += Dir.glob(pattern).map do |path|
Pathname.new(path.gsub("\\", "/")).cleanpath.to_s
end
end.sort
end
# Make a relative path corresponding to a possibly absolute one. # Make a relative path corresponding to a possibly absolute one.
# #
# @param path [String] # @param path [String]
+1 -1
View File
@@ -1,4 +1,4 @@
module Rscons module Rscons
# Project version. # Project version.
VERSION = "3.2.0" VERSION = "3.3.0"
end end
+45 -10
View File
@@ -1,7 +1,10 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
require "fileutils" require "base64"
require "digest/md5" require "digest/md5"
require "fileutils"
require "stringio"
require "zlib"
if File.read("lib/rscons/version.rb") =~ /VERSION = "(.+)"/ if File.read("lib/rscons/version.rb") =~ /VERSION = "(.+)"/
VERSION = $1 VERSION = $1
@@ -68,11 +71,15 @@ license = File.read("LICENSE.txt").gsub(/^(.*?)$/) do |line|
end end
end end
require "zlib"
require "base64"
compressed_script = Zlib::Deflate.deflate(stripped.join) compressed_script = Zlib::Deflate.deflate(stripped.join)
hash = Digest::MD5.hexdigest(compressed_script)
encoded_compressed_script = Base64.encode64(compressed_script).gsub("\n", "") encoded_compressed_script = Base64.encode64(compressed_script).gsub("\n", "")
hash = Digest::MD5.hexdigest(encoded_compressed_script) encoded_compressed_script_io = StringIO.new(encoded_compressed_script)
commented_encoded_compressed_script = ""
until encoded_compressed_script_io.eof?
line = encoded_compressed_script_io.read(64)
commented_encoded_compressed_script += "##{line}\n"
end
FileUtils.rm_rf(DIST) FileUtils.rm_rf(DIST)
FileUtils.mkdir_p(DIST) FileUtils.mkdir_p(DIST)
@@ -82,25 +89,53 @@ File.open("#{DIST}/#{PROG_NAME}", "wb", 0755) do |fh|
#{license} #{license}
BASE64CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
def base64_decode(s)
out = ""
v = 0
bits = 0
s.each_char do |c|
if cv = BASE64CHARS.index(c)
v = (v << 6) | cv
bits += 6
elsif c == "="
break
end
if bits >= 8
out += (v >> (bits - 8)).chr
v &= 0xFFFFFFFF >> (32 - (bits - 8))
bits -= 8
end
end
out
end
script = File.join(File.dirname(__FILE__), ".rscons-#{VERSION}-#{hash}.rb") script = File.join(File.dirname(__FILE__), ".rscons-#{VERSION}-#{hash}.rb")
unless File.exist?(script) unless File.exist?(script)
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/ if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/m
require "zlib" require "zlib"
require "base64"
encoded_compressed = $1 encoded_compressed = $1
unescaped_compressed = Base64.decode64(encoded_compressed) compressed = base64_decode(encoded_compressed)
inflated = Zlib::Inflate.inflate(unescaped_compressed) if ENV["rscons_dist_specs"]
require "digest/md5"
if Digest::MD5.hexdigest(compressed) != "#{hash}"
raise "Hash mismatch when decompressing rscons executable"
end
end
inflated = Zlib::Inflate.inflate(compressed)
File.open(script, "wb") do |fh| File.open(script, "wb") do |fh|
fh.write(inflated) fh.write(inflated)
end end
else else
raise "Could not decompress." raise "Error expanding rscons executable"
end end
end end
load script load script
if __FILE__ == $0 if __FILE__ == $0
Rscons::Cli.new.run(ARGV) Rscons::Cli.new.run(ARGV)
end end
#==>#{encoded_compressed_script} #==>
#{commented_encoded_compressed_script}
EOF EOF
end end
+46 -38
View File
@@ -665,15 +665,15 @@ EOF
expect(result.stdout).to eq "" expect(result.stdout).to eq ""
end end
unless RUBY_PLATFORM =~ /mingw|msys/ unless RUBY_PLATFORM =~ /mingw|msys|darwin/
it "supports building D sources with gdc" do it "supports building D sources with gdc" do
test_dir("d") test_dir("d")
result = run_rscons result = run_rscons
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
slines = lines(result.stdout) slines = lines(result.stdout)
verify_lines(slines, [%r{gdc -c -o build/o/main.d.o -MMD -MF build/o/main.d.o.mf main.d}]) verify_lines(slines, [%r{gdc -c -o build/o/src/main.d.o .* src/main.d}])
verify_lines(slines, [%r{gdc -c -o build/o/mod.d.o -MMD -MF build/o/mod.d.o.mf mod.d}]) verify_lines(slines, [%r{gdc -c -o build/o/src/mod.d.o .* src/mod.d}])
verify_lines(slines, [%r{gdc -o hello-d.exe build/o/main.d.o build/o/mod.d.o}]) verify_lines(slines, [%r{gdc -o hello-d.exe build/o/src/main.d.o build/o/src/mod.d.o}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!" expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
end end
end end
@@ -683,9 +683,9 @@ EOF
result = run_rscons(args: %w[-f build-ldc2.rb]) result = run_rscons(args: %w[-f build-ldc2.rb])
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
slines = lines(result.stdout) slines = lines(result.stdout)
verify_lines(slines, [%r{ldc2 -c -of build/o/main.d.o(bj)? -deps=build/o/main.d.o(bj)?.mf main.d}]) verify_lines(slines, [%r{ldc2 -c -of build/o/src/main.d.o(bj)? -deps=build/o/src/main.d.o(bj)?.mf.* src/main.d}])
verify_lines(slines, [%r{ldc2 -c -of build/o/mod.d.o(bj)? -deps=build/o/mod.d.o(bj)?.mf mod.d}]) verify_lines(slines, [%r{ldc2 -c -of build/o/src/mod.d.o(bj)? -deps=build/o/src/mod.d.o(bj)?.mf.* src/mod.d}])
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/o/main.d.o(bj)? build/o/mod.d.o(bj)?}]) verify_lines(slines, [%r{ldc2 -of hello-d.exe build/o/src/main.d.o(bj)? build/o/src/mod.d.o(bj)?}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!" expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
end end
@@ -694,24 +694,24 @@ EOF
result = run_rscons(args: %w[-f build-ldc2.rb]) result = run_rscons(args: %w[-f build-ldc2.rb])
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
slines = lines(result.stdout) slines = lines(result.stdout)
verify_lines(slines, [%r{ldc2 -c -of build/o/main.d.o(bj)? -deps=build/o/main.d.o(bj)?.mf main.d}]) verify_lines(slines, [%r{ldc2 -c -of build/o/src/main.d.o(bj)? -deps=build/o/src/main.d.o(bj)?.mf.* src/main.d}])
verify_lines(slines, [%r{ldc2 -c -of build/o/mod.d.o(bj)? -deps=build/o/mod.d.o(bj)?.mf mod.d}]) verify_lines(slines, [%r{ldc2 -c -of build/o/src/mod.d.o(bj)? -deps=build/o/src/mod.d.o(bj)?.mf.* src/mod.d}])
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/o/main.d.o(bj)? build/o/mod.d.o(bj)?}]) verify_lines(slines, [%r{ldc2 -of hello-d.exe build/o/src/main.d.o(bj)? build/o/src/mod.d.o(bj)?}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!" expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
contents = File.read("mod.d", mode: "rb").sub("42", "33") contents = File.read("src/mod.d", mode: "rb").sub("42", "33")
File.open("mod.d", "wb") do |fh| File.open("src/mod.d", "wb") do |fh|
fh.write(contents) fh.write(contents)
end end
result = run_rscons(args: %w[-f build-ldc2.rb]) result = run_rscons(args: %w[-f build-ldc2.rb])
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
slines = lines(result.stdout) slines = lines(result.stdout)
verify_lines(slines, [%r{ldc2 -c -of build/o/main.d.o(bj)? -deps=build/o/main.d.o(bj)?.mf main.d}]) verify_lines(slines, [%r{ldc2 -c -of build/o/src/main.d.o(bj)? -deps=build/o/src/main.d.o(bj)?.mf.* src/main.d}])
verify_lines(slines, [%r{ldc2 -c -of build/o/mod.d.o(bj)? -deps=build/o/mod.d.o(bj)?.mf mod.d}]) verify_lines(slines, [%r{ldc2 -c -of build/o/src/mod.d.o(bj)? -deps=build/o/src/mod.d.o(bj)?.mf.* src/mod.d}])
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/o/main.d.o(bj)? build/o/mod.d.o(bj)?}]) verify_lines(slines, [%r{ldc2 -of hello-d.exe build/o/src/main.d.o(bj)? build/o/src/mod.d.o(bj)?}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 33!" expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 33!"
end end
unless RUBY_PLATFORM =~ /mingw|msys/ unless RUBY_PLATFORM =~ /mingw|msys|darwin/
it "links with the D linker when object files were built from D sources" do it "links with the D linker when object files were built from D sources" do
test_dir("d") test_dir("d")
result = run_rscons(args: %w[-f link_objects.rb]) result = run_rscons(args: %w[-f link_objects.rb])
@@ -726,18 +726,18 @@ EOF
result = run_rscons result = run_rscons
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
slines = lines(result.stdout) slines = lines(result.stdout)
verify_lines(slines, [%r{gdc -c -o build/o/main.d.o -MMD -MF build/o/main.d.o.mf main.d}]) verify_lines(slines, [%r{gdc -c -o build/o/src/main.d.o -MMD -MF build/o/src/main.d.o.mf.* src/main.d}])
verify_lines(slines, [%r{gdc -c -o build/o/mod.d.o -MMD -MF build/o/mod.d.o.mf mod.d}]) verify_lines(slines, [%r{gdc -c -o build/o/src/mod.d.o -MMD -MF build/o/src/mod.d.o.mf.* src/mod.d}])
verify_lines(slines, [%r{gdc -o hello-d.exe build/o/main.d.o build/o/mod.d.o}]) verify_lines(slines, [%r{gdc -o hello-d.exe build/o/src/main.d.o build/o/src/mod.d.o}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!" expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
fcontents = File.read("mod.d", mode: "rb").sub("42", "33") fcontents = File.read("src/mod.d", mode: "rb").sub("42", "33")
File.open("mod.d", "wb") {|fh| fh.write(fcontents)} File.open("src/mod.d", "wb") {|fh| fh.write(fcontents)}
result = run_rscons result = run_rscons
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
slines = lines(result.stdout) slines = lines(result.stdout)
verify_lines(slines, [%r{gdc -c -o build/o/main.d.o -MMD -MF build/o/main.d.o.mf main.d}]) verify_lines(slines, [%r{gdc -c -o build/o/src/main.d.o -MMD -MF build/o/src/main.d.o.mf.* src/main.d}])
verify_lines(slines, [%r{gdc -c -o build/o/mod.d.o -MMD -MF build/o/mod.d.o.mf mod.d}]) verify_lines(slines, [%r{gdc -c -o build/o/src/mod.d.o -MMD -MF build/o/src/mod.d.o.mf.* src/mod.d}])
verify_lines(slines, [%r{gdc -o hello-d.exe build/o/main.d.o build/o/mod.d.o}]) verify_lines(slines, [%r{gdc -o hello-d.exe build/o/src/main.d.o build/o/src/mod.d.o}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 33!" expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 33!"
end end
@@ -761,7 +761,7 @@ EOF
result = run_rscons(args: %w[-f disassemble.rb]) result = run_rscons(args: %w[-f disassemble.rb])
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
expect(File.exist?("simple.txt")).to be_truthy expect(File.exist?("simple.txt")).to be_truthy
expect(File.read("simple.txt")).to match /Disassembly of section .text:/ expect(File.read("simple.txt")).to match /Disassembly of section/
result = run_rscons(args: %w[-f disassemble.rb]) result = run_rscons(args: %w[-f disassemble.rb])
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
@@ -1211,7 +1211,7 @@ EOF
%r{Compiling simple.c}, %r{Compiling simple.c},
%r{My Disassemble simple.txt}, %r{My Disassemble simple.txt},
]) ])
expect(File.read("simple.txt")).to match /Disassembly of section .text:/ expect(File.read("simple.txt")).to match /Disassembly of section/
end end
end end
@@ -1347,6 +1347,14 @@ EOF
%r{Checker simple.exe}, %r{Checker simple.exe},
]) ])
end end
it "supports phony targets as dependencies" do
test_dir "typical"
result = run_rscons(args: %w[-f phonies.rb])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to match /t1.*phony2.*t2.*phony1.*t3/m
end
end end
context "Environment#clear_targets" do context "Environment#clear_targets" do
@@ -2024,7 +2032,7 @@ EOF
{"check_d_compiler.rb" => "when no arguments are given", {"check_d_compiler.rb" => "when no arguments are given",
"check_d_compiler_find_first.rb" => "when arguments are given"}.each_pair do |rsconscript, desc| "check_d_compiler_find_first.rb" => "when arguments are given"}.each_pair do |rsconscript, desc|
context desc do context desc do
unless RUBY_PLATFORM =~ /mingw|msys/ unless RUBY_PLATFORM =~ /mingw|msys|darwin/
it "finds the first listed D compiler" do it "finds the first listed D compiler" do
test_dir "configure" test_dir "configure"
result = run_rscons(args: %W[-f #{rsconscript} configure]) result = run_rscons(args: %W[-f #{rsconscript} configure])
@@ -2056,18 +2064,18 @@ EOF
end end
end end
it "respects use flag" do unless RUBY_PLATFORM =~ /mingw|msys|darwin/
test_dir "configure" it "respects use flag" do
result = run_rscons(args: %w[-f check_d_compiler_use.rb -v]) test_dir "configure"
expect(result.stderr).to eq "" result = run_rscons(args: %w[-f check_d_compiler_use.rb -v])
expect(result.status).to eq 0 expect(result.stderr).to eq ""
expect(result.stdout).to match %r{\bgdc .*/t1/} expect(result.status).to eq 0
expect(result.stdout).to_not match %r{\bldc2 .*/t1/} expect(result.stdout).to match %r{\bgdc .*/t1/}
expect(result.stdout).to match %r{\bldc2 .*/t2/} expect(result.stdout).to_not match %r{\bldc2 .*/t1/}
expect(result.stdout).to_not match %r{\bgdc .*/t2/} expect(result.stdout).to match %r{\bldc2 .*/t2/}
end expect(result.stdout).to_not match %r{\bgdc .*/t2/}
end
unless RUBY_PLATFORM =~ /mingw|msys/
it "successfully tests a compiler with an unknown name that uses gdc-compatible options" do it "successfully tests a compiler with an unknown name that uses gdc-compatible options" do
test_dir "configure" test_dir "configure"
create_exe "mycompiler", %[exec gdc "$@"] create_exe "mycompiler", %[exec gdc "$@"]
+2 -7
View File
@@ -1,4 +1,4 @@
if ENV["dist_specs"] if ENV["rscons_dist_specs"]
require_relative "../test/rscons" require_relative "../test/rscons"
else else
require "simplecov" require "simplecov"
@@ -11,12 +11,7 @@ else
else else
command_name "RSpec" command_name "RSpec"
end end
if ENV["dist_specs"] add_filter "test/rscons.rb"
add_filter "/bin/"
add_filter "/lib/"
else
add_filter "test/rscons.rb"
end
project_name "Rscons" project_name "Rscons"
merge_timeout 3600 merge_timeout 3600
end end