Compare commits

...

10 Commits

Author SHA1 Message Date
1932b65992 WIP - parallel tests 2026-01-25 22:01:58 -05:00
94a86e3433 Add Barrier builder 2026-01-16 22:54:22 -05:00
fc18c9f123 Test phony dependencies 2026-01-16 20:21:13 -05:00
1d020d1aef Update gems 2026-01-15 21:07:18 -05:00
19c5c8cfba Update gems 2025-11-22 00:14:26 -05:00
4fc7ab6b25 v3.3.0 2025-06-10 20:14:15 -04:00
161da80ffe Update CHANGELOG for v3.3.0 2025-06-10 20:13:37 -04:00
8d9f19cb34 Add github workflow to run RScons tests
Fix up some macOS test cases
2025-06-08 20:46:09 -04:00
18a2a075c1 Remove dependency on base64 - close #177 2025-06-08 02:48:03 -04:00
1a280a8994 Update gems 2025-06-07 20:30:48 -04:00
18 changed files with 3621 additions and 3477 deletions

38
.github/workflows/run-tests.yml vendored Normal file
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

2
.gitignore vendored
View File

@ -7,5 +7,5 @@
/gen/ /gen/
/large_project/ /large_project/
/pkg/ /pkg/
/test/ /test_run/
/yard/ /yard/

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

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

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

View File

@ -1,4 +1,4 @@
Copyright (c) 2013-2022 Josh Holtrop Copyright (c) 2013-2025 Josh Holtrop
MIT License MIT License

View File

@ -9,7 +9,7 @@ require "rspec/core/rake_task"
require "rake/clean" require "rake/clean"
require "fileutils" require "fileutils"
CLEAN.include %w[build_test_run .yardoc yard coverage test] CLEAN.include %w[build_test_run .yardoc yard coverage test_run]
CLOBBER.include %w[dist gen large_project pkg] CLOBBER.include %w[dist gen large_project pkg]
task :build_dist do task :build_dist do
@ -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.mkdir_p("test") FileUtils.rm_rf("test_run")
FileUtils.cp("dist/rscons", "test/rscons.rb") FileUtils.mkdir_p("test_run")
ENV["dist_specs"] = "1" FileUtils.cp("dist/rscons", "test_run/rscons.rb")
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

3439
build_tests/build_tests.rb Normal file

File diff suppressed because it is too large Load Diff

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

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

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,
@ -66,6 +67,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 +144,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"

View File

@ -37,7 +37,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

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

View File

@ -397,7 +397,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[target] + user_deps).each do |ud|
unless Rscons.phony_target?(ud) || @user_deps[target].include?(ud)
@user_deps[target] << ud
end
end
build_after(target, user_deps) build_after(target, user_deps)
end end
@ -623,7 +627,9 @@ module Rscons
# #
# @return [void] # @return [void]
def run_builder(builder) def run_builder(builder)
unless builder.is_a?(Rscons::Builders::Barrier)
builder.build_step ||= get_next_build_step 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,9 +655,11 @@ 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
unless builder.is_a?(Rscons::Builders::Barrier)
@build_hooks[:post].each do |build_hook_block| @build_hooks[:post].each do |build_hook_block|
build_hook_block.call(builder) build_hook_block.call(builder)
end end
end
process_remove_wait(builder) process_remove_wait(builder)
else else
raise "Unrecognized #{builder.name} builder return value: #{result.inspect}" raise "Unrecognized #{builder.name} builder return value: #{result.inspect}"
@ -727,9 +735,11 @@ module Rscons
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)
unless builder.is_a?(Rscons::Builders::Barrier)
@build_hooks[:pre].each do |build_hook_block| @build_hooks[:pre].each do |build_hook_block|
build_hook_block.call(builder) build_hook_block.call(builder)
end end
end
return run_builder(builder) return run_builder(builder)
end end
end end

View File

@ -1,4 +1,4 @@
module Rscons module Rscons
# Project version. # Project version.
VERSION = "3.2.0" VERSION = "3.3.0"
end end

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

File diff suppressed because it is too large Load Diff

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 "/bin/"
add_filter "/lib/"
else
add_filter "test/rscons.rb" add_filter "test/rscons.rb"
end
project_name "Rscons" project_name "Rscons"
merge_timeout 3600 merge_timeout 3600
end end