aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-10-07 02:25:34 +0200
committerEugen Wissner <belka@caraus.de>2026-10-07 02:25:34 +0200
commitf9dfefc52fc792099b622ae47dafa32d2512e51e (patch)
tree3be1fdc6d29bf04dc460684794ebfc566f7a2662
parente38f23a1bd6e0ee093655e1f241e524795f21fec (diff)
downloadelna-f9dfefc52fc792099b622ae47dafa32d2512e51e.tar.gz
Add some useful gems for ruby code
-rw-r--r--.gitignore4
-rw-r--r--.rubocop.yml30
-rw-r--r--Gemfile12
-rw-r--r--Gemfile.lock139
-rw-r--r--Rakefile7
-rw-r--r--rakelib/compiler.rake7
-rw-r--r--rakelib/doc.rake1
-rw-r--r--rakelib/gcc.rake215
-rw-r--r--rakelib/ruby.rake11
-rw-r--r--rakelib/support/ui.rb25
-rw-r--r--rakelib/treesitter.rake9
11 files changed, 336 insertions, 124 deletions
diff --git a/.gitignore b/.gitignore
index bcbf68f..d06ffb4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,10 @@ jit/
.cache/
/compile_commands.json
+# Tree-sitter.
*.o
*.so
node_modules/
+
+# Ruby.
+/vendor/
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..d69ffc7
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,30 @@
+plugins:
+ - rubocop-rake
+
+AllCops:
+ TargetRubyVersion: 4.0
+ NewCops: enable
+ SuggestExtensions: false
+ Include:
+ - 'Rakefile'
+ - 'rakelib/**/*'
+
+Metrics/BlockLength:
+ AllowedMethods:
+ - namespace
+ - task
+
+Layout/ArgumentAlignment:
+ EnforcedStyle: with_fixed_indentation
+
+Layout/ParameterAlignment:
+ EnforcedStyle: with_fixed_indentation
+
+Layout/ArrayAlignment:
+ EnforcedStyle: with_fixed_indentation
+
+Layout/MultilineMethodCallIndentation:
+ EnforcedStyle: indented
+
+Layout/MultilineOperationIndentation:
+ EnforcedStyle: indented
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..42188c7
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gem 'rake', '~> 13.4'
+gem 'rubocop', '~> 1.91'
+gem 'rubocop-rake', '~> 0.7'
+
+gem 'faraday', '~> 2.14'
+gem 'faraday-follow_redirects', '~> 0.5'
+
+gem 'term-ansicolor', '~> 1.11'
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..1c40795
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,139 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ ast (2.4.3)
+ bigdecimal (4.1.3)
+ erb (6.0.7)
+ faraday (2.14.4)
+ faraday-net_http (>= 2.0, < 3.5)
+ json
+ logger
+ faraday-follow_redirects (0.5.0)
+ faraday (>= 1, < 3)
+ faraday-net_http (3.4.4)
+ net-http (~> 0.5)
+ io-console (0.9.4)
+ irb (1.18.0)
+ pp (>= 0.6.0)
+ prism (>= 1.3.0)
+ rdoc (>= 4.0.0)
+ reline (>= 0.4.2)
+ json (3.0.2)
+ language_server-protocol (3.17.0.6)
+ lint_roller (1.1.0)
+ logger (1.7.0)
+ mize (0.6.1)
+ net-http (0.9.1)
+ uri (>= 0.11.1)
+ parallel (2.3.0)
+ parser (3.3.12.0)
+ ast (~> 2.4.1)
+ racc
+ pp (0.6.4)
+ prettyprint
+ prettyprint (0.2.0)
+ prism (1.9.0)
+ racc (1.8.1)
+ rainbow (3.1.1)
+ rake (13.4.2)
+ rbs (4.2.0)
+ logger
+ prism (>= 1.6.0)
+ tsort
+ rdoc (8.1.0)
+ erb
+ prism (>= 1.6.0)
+ rbs (>= 4.0.0)
+ tsort
+ readline (0.0.4)
+ reline
+ regexp_parser (2.13.1)
+ reline (0.7.0)
+ io-console (~> 0.5)
+ rubocop (1.91.0)
+ json (>= 2.3)
+ language_server-protocol (~> 3.17.0.2)
+ lint_roller (~> 1.1.0)
+ parallel (>= 1.10)
+ parser (>= 3.3.0.2)
+ rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 2.9.3, < 3.0)
+ rubocop-ast (>= 1.49.0, < 2.0)
+ ruby-progressbar (~> 1.7)
+ unicode-display_width (>= 2.4.0, < 4.0)
+ rubocop-ast (1.50.0)
+ parser (>= 3.3.7.2)
+ prism (~> 1.7)
+ rubocop-rake (0.7.1)
+ lint_roller (~> 1.1)
+ rubocop (>= 1.72.1)
+ ruby-progressbar (1.13.0)
+ sync (0.5.0)
+ term-ansicolor (1.11.3)
+ tins (~> 1)
+ tins (1.60.0)
+ bigdecimal
+ irb
+ mize (~> 0.6)
+ readline
+ sync
+ tsort (0.2.0)
+ unicode-display_width (3.3.0)
+ unicode-emoji (~> 4.3)
+ unicode-emoji (4.3.0)
+ uri (1.1.1)
+
+PLATFORMS
+ ruby
+ x86_64-linux
+
+DEPENDENCIES
+ faraday (~> 2.14)
+ faraday-follow_redirects (~> 0.5)
+ rake (~> 13.4)
+ rubocop (~> 1.91)
+ rubocop-rake (~> 0.7)
+ term-ansicolor (~> 1.11)
+
+CHECKSUMS
+ ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
+ bigdecimal (4.1.3) sha256=61ebe1e5e559bdc3cc6f2c0ee7f427321fc838f59611c294356eb04d6e21cf66
+ erb (6.0.7) sha256=c5ca6dc25b0ef974a44dc8f59fe847577122483b1968a38dec305c60bf91ee92
+ faraday (2.14.4) sha256=9bb4408c44621b0dbaaaa39e5dbfc4dbe58cc6751b6eb94d16ae9e1f2f2fab6e
+ faraday-follow_redirects (0.5.0) sha256=5cde93c894b30943a5d2b93c2fe9284216a6b756f7af406a1e55f211d97d10ad
+ faraday-net_http (3.4.4) sha256=0e78af151747ed1b00f33e25973b4bc220d7f16c00c39676817c8b12331eb588
+ io-console (0.9.4) sha256=a403304f32928ee85e56d457b4612ca43f2703b561a3258844992bd24085fbb1
+ irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
+ json (3.0.2) sha256=8e6d7e7b11384c21230430cef90b71f14849a34a1f4452796670f7c981bd19df
+ language_server-protocol (3.17.0.6) sha256=5ef2c0c138f8267e1bc631d3328347d354f96724b0af22f2c79516120443b7f0
+ lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
+ logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
+ mize (0.6.1) sha256=4031558979ff5426fda24c75a149b4e4c0faf4cacf2fae8938f83866ab94b780
+ net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996
+ parallel (2.3.0) sha256=f75a3e904101ce6a1ccb6b8dc800cbafd42166d83330192438dcf29395167a6f
+ parser (3.3.12.0) sha256=21a6d7f755d5a24dfbdc6e6b772e4e879a52e7631a88bc5a3a134606052c9828
+ pp (0.6.4) sha256=dfcb0fce700c41456265922884f9fe195d7fbb0674a3578e6c0f69588e82b570
+ prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
+ prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
+ racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
+ rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
+ rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
+ rbs (4.2.0) sha256=51f7b886dcc05bc09e10b901daa6a81829f6adc03101d6ca9ea4aac6103e0674
+ rdoc (8.1.0) sha256=befc37880a5cfd36dcb176c748b5fd5ee39dd3536a75e81824e4972ce230f60a
+ readline (0.0.4) sha256=6138eef17be2b98298b672c3ea63bf9cb5158d401324f26e1e84f235879c1d6a
+ regexp_parser (2.13.1) sha256=5aedb6b7c35688f51e86eef17a15374dfd287c83f4ca644b2c5f3ec50a33b44b
+ reline (0.7.0) sha256=5b012d8e55dbf9d450f12bde2cf7d15ff546ae80b3f8f3b30e570d431815583d
+ rubocop (1.91.0) sha256=9c82b7bf391c5d7e3798c5b9996e22a1fe3bd7468e351dfdeb96140c058296d0
+ rubocop-ast (1.50.0) sha256=b9ca88300da0803ee222ad20cdb30494c0a784eed06fdc35d254b06d662788db
+ rubocop-rake (0.7.1) sha256=3797f2b6810c3e9df7376c26d5f44f3475eda59eb1adc38e6f62ecf027cbae4d
+ ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
+ sync (0.5.0) sha256=668356cc07c59ac7ed9ecf34fec3929831f179c07adb1f3e1c3b7a1609a638fd
+ term-ansicolor (1.11.3) sha256=8c01ec3abd095eb94dca8aed5a127d36e594239eb525eb306259c9e930534603
+ tins (1.60.0) sha256=919f9b6e4cc3aa0d80fb37d43118c8fb093462a4482bbcf2728bde47d4a80791
+ tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
+ unicode-display_width (3.3.0) sha256=4b7aa66a4b11db50f6f7e98411215cd0dd10eaecb665d36eec5bcacb3fa0b613
+ unicode-emoji (4.3.0) sha256=11c02fa73290378c066bb0562cd4c87d8e1b706fbbe0059ca12746a4244de8ce
+ uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
+
+BUNDLED WITH
+ 4.0.20
diff --git a/Rakefile b/Rakefile
index a5e0ebd..5adb525 100644
--- a/Rakefile
+++ b/Rakefile
@@ -7,9 +7,8 @@ require 'rake/clean'
CLOBBER.include 'build'
-task default: 'source/main.elna'
-task default: 'build/gcc/elna' do |t|
- sources, compiler = t.prerequisites.partition { |f| f.end_with? '.elna' }
+task default: ['source/main.elna', 'build/gcc/elna'] do |t|
+ sources, compiler = t.prerequisites.partition { |f| f.end_with? '.elna' }
- sh *compiler, '--parse', *sources
+ sh(*compiler, '--parse', *sources)
end
diff --git a/rakelib/compiler.rake b/rakelib/compiler.rake
index f443407..4731e1d 100644
--- a/rakelib/compiler.rake
+++ b/rakelib/compiler.rake
@@ -11,7 +11,7 @@ CLEAN.include 'build/gcc'
Rake.application.add_loader('d', Rake::MakefileLoader.new)
FileList['build/gcc/**/*.d'].each { |file| import file }
-rule(/gcc\/.+\.o$/ => ->(file) {
+rule(%r{gcc/.+\.o$} => lambda { |file|
source = Pathname.new('source') +
Pathname.new(file).relative_path_from('build/gcc').sub_ext('.elna')
@@ -22,9 +22,8 @@ rule(/gcc\/.+\.o$/ => ->(file) {
sh t.prerequisites.last, '-c', '-MD', '-MP', '-O0', '-g', '-I', 'source', '-o', t.name, t.source.to_s
end
-file 'build/gcc/elna' => FileList['source/**/*.elna'].reject { |file|
- file != file.downcase
-}.map { |file|
+sources = FileList['source/**/*.elna'].select { |file| file == file.downcase }
+file 'build/gcc/elna' => sources.map { |file|
Pathname.new('build/gcc') +
Pathname.new(file).relative_path_from('source').sub_ext('.o')
} do |t|
diff --git a/rakelib/doc.rake b/rakelib/doc.rake
index 5f40107..bf92293 100644
--- a/rakelib/doc.rake
+++ b/rakelib/doc.rake
@@ -18,6 +18,7 @@ rule '.bbl' => '.bcf' do |t|
end
namespace :doc do
+ desc 'Compile LaTeX documentation'
task tex: 'build/doc' do |t|
sh 'pdflatex', '-output-directory', "../#{t.prerequisites.first}", 'report',
chdir: 'doc'
diff --git a/rakelib/gcc.rake b/rakelib/gcc.rake
index 7ee9f5c..6dce877 100644
--- a/rakelib/gcc.rake
+++ b/rakelib/gcc.rake
@@ -5,8 +5,18 @@
require 'fileutils'
require 'uri'
-require 'net/http'
-require 'open3'
+require 'faraday'
+require 'faraday/follow_redirects'
+require 'English'
+require_relative 'support/ui'
+
+# Dependencies.
+GCC_VERSION = '16.2.0'
+GCC_HOST = 'build/host/gcc'
+GCC_HOST_INSTALL = Pathname.new 'build/host/install'
+GCC_TREE = Pathname.new "build/tools/gcc-#{GCC_VERSION}"
+GCC_PATCH =
+ "https://raw.githubusercontent.com/Homebrew/homebrew-core/refs/heads/main/Patches/gcc/gcc-#{GCC_VERSION}.diff".freeze
# Use Homebrew GCC if available (it uses libstdc++, avoiding
# macOS-specific libc++ incompatibilities in GCC's own sources).
@@ -34,59 +44,50 @@ end
def gcc_verbose(gcc_binary)
read, write = IO.pipe
- sh({'LC_ALL' => 'C'}, gcc_binary, '--verbose', err: write)
+ sh({ 'LC_ALL' => 'C' }, gcc_binary, '--verbose', err: write)
write.close
output = read.read
read.close
output
end
-def find_build_target(gcc_version)
- if RUBY_PLATFORM =~ /darwin/
- suffix = '-' + gcc_version.split('.').first
- mac_os_sdk = '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk'
- else
- suffix = ''
- end
- build_target = gcc_verbose(ENV.fetch 'CC', "gcc#{suffix}")
+def target_triple(cc_name)
+ gcc_verbose(cc_name)
.lines
.find { |line| line.start_with? 'Target: ' }
- .split(' ')
+ .split
.last
.strip
+end
+
+def find_build_target(gcc_version)
+ is_darwin = RUBY_PLATFORM =~ /darwin/
+ suffix = is_darwin ? "-#{gcc_version.split('.').first}" : ''
+ mac_os_sdk = '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk' if is_darwin
+ build_target = target_triple(ENV.fetch('CC', "gcc#{suffix}"))
GCCConfiguration.new suffix, build_target, mac_os_sdk
end
+def pipe_to_command(command, chdir:, &)
+ IO.popen(command, 'w', chdir:, &)
+ UI.fatal "Command #{command.join(' ')} failed" unless $CHILD_STATUS.success?
+end
+
+def stream_http(url, &)
+ conn = Faraday.new do |f|
+ f.response :follow_redirects
+ f.response :raise_error
+ end
+ conn.get(url) do |req|
+ req.options.on_data = ->(chunk, _, env) { yield chunk if (200..299).cover?(env.status) && !chunk.empty? }
+ end
+end
+
def download_and_pipe(url, target, command)
target.mkpath
-
- Net::HTTP.start(url.host, url.port, use_ssl: url.scheme == 'https') do |http|
- request = Net::HTTP::Get.new url.request_uri
-
- http.request request do |response|
- case response
- when Net::HTTPRedirection
- download_and_pipe URI.parse(response['location']), target, command
- when Net::HTTPSuccess
- Dir.chdir target.to_path do
- Open3.popen2(*command) do |stdin, stdout, wait_thread|
- Thread.new do
- stdout.each { |line| puts line }
- end
-
- response.read_body do |chunk|
- stdin.write chunk
- end
- stdin.close
-
- wait_thread.value
- end
- end
- else
- response.error!
- end
- end
+ pipe_to_command(command, chdir: target.to_path) do |stdin|
+ stream_http(url) { |chunk| stdin.write chunk }
end
end
@@ -104,60 +105,69 @@ def convert_directive(line, directive, dg_name)
end
end
+def test_trailer_lines(category, extra_lines = [])
+ lines = []
+ lines << '(* { dg-do run } *)' if category == 'runnable'
+ lines.concat extra_lines
+ lines << '(* { dg-prune-output .* } *)'
+ case category
+ when 'compilable' then lines << '(* { dg-final { output-exists } } *)'
+ when 'fail_compilation' then lines << '(* { dg-final { output-exists-not } } *)'
+ end
+ lines
+end
+
def convert_test(source, target, category, extra_lines = [])
File.open(target, 'wb') do |output|
File.foreach(source) do |line|
line = convert_directive(line, '@Error', 'dg-error')
- line = convert_directive(line, '@Flags', 'dg-additional-options')
-
- output.puts line
+ output.puts convert_directive(line, '@Flags', 'dg-additional-options')
end
- # Runnable tests compile, link and execute.
- output.puts '(* { dg-do run } *)' if category == 'runnable'
+ test_trailer_lines(category, extra_lines).each { |line| output.puts line }
+ end
+end
+
+def multi_module_extra_sources(test_target)
+ sources = test_target.glob('**/*.elna')
+ .map { |extra| %("#{extra.relative_path_from(test_target)}") }
+ "(* { dg-additional-sources #{sources * ' '} } *)"
+end
- extra_lines.each { |line| output.puts line }
+def convert_multi_module_test(test_path, test_target, category)
+ main = test_path / 'sut.elna'
+ UI.fatal "Multi-module test directory \"#{test_path}\" must contain sut.elna." unless main.file?
- # Suppress excess output so stray diagnostics do not fail the test.
- output.puts '(* { dg-prune-output .* } *)'
+ test_target.mkdir
+ (test_path.children - [main]).each { |extra| cp_r extra, test_target }
+ extra_lines = ["(* { dg-additional-options \"-I#{test_target.expand_path}\" } *)"]
+ extra_lines << multi_module_extra_sources(test_target) if category == 'runnable'
- case category
- when 'compilable'
- # Assert that an output file was produced.
- output.puts '(* { dg-final { output-exists } } *)'
- when 'fail_compilation'
- # Assert that no output file was produced.
- output.puts '(* { dg-final { output-exists-not } } *)'
- end
- end
+ convert_test main, test_target / 'sut.elna', category, extra_lines
end
namespace :gcc do
- # Dependencies.
- GCC_VERSION = "16.2.0"
- HOST_GCC = 'build/host/gcc'
- HOST_INSTALL = Pathname.new 'build/host/install'
- GCC_TREE = Pathname.new "build/tools/gcc-#{GCC_VERSION}"
- GCC_PATCH =
- "https://raw.githubusercontent.com/Homebrew/homebrew-core/refs/heads/main/Patches/gcc/gcc-#{GCC_VERSION}.diff"
-
- directory HOST_GCC
- directory HOST_INSTALL.to_path
+ directory GCC_HOST
+ directory GCC_HOST_INSTALL.to_path
directory 'build/tools'
desc 'Download the bootstrap compiler and its prerequisites'
task download: 'build/tools' do
+ UI.step "Downloading bootstrap compiler and prerequisites (GCC #{GCC_VERSION})..."
url = URI.parse "https://gcc.gnu.org/pub/gcc/releases/gcc-#{GCC_VERSION}/gcc-#{GCC_VERSION}.tar.xz"
+ UI.debug "Downloading #{url}..."
download_and_pipe url, GCC_TREE.dirname, ['tar', '-Jxv']
+ UI.debug "Downloading and applying patch #{GCC_PATCH}..."
download_and_pipe URI.parse(GCC_PATCH), GCC_TREE, ['patch', '-p1']
# GCC 16.1.0 registers 17 languages but CL_PARAMS is at bit 16,
# which collides with the 17th language class (CL_Rust). Shift
# every CL_* constant from bit 16 upward by one position.
- File.open(GCC_TREE + 'gcc/opts.h', 'r+') do |opts_h|
- content = opts_h.read.gsub(/\(1U << (\d+)\)/) do |m|
- "(1U << #{$1.to_i + 1})"
+ UI.debug 'Patching gcc/opts.h to shift CL_* flags...'
+ File.open(GCC_TREE / 'gcc/opts.h', 'r+') do |opts_h|
+ content = opts_h.read.gsub(/\(1U << (\d+)\)/) do
+ "(1U << #{Regexp.last_match(1).to_i + 1})"
end
opts_h.seek 0, IO::SEEK_SET
opts_h.write content
@@ -168,8 +178,9 @@ namespace :gcc do
desc 'Link the frontend into the GCC source tree'
task :link do
- source_destination = GCC_TREE + 'gcc/elna'
- test_destination = GCC_TREE + 'gcc/testsuite/elna.dg'
+ UI.step 'Linking Elna frontend into the GCC source tree...'
+ source_destination = GCC_TREE / 'gcc/elna'
+ test_destination = GCC_TREE / 'gcc/testsuite/elna.dg'
rm_rf [source_destination, test_destination]
mkdir_p [source_destination, test_destination]
@@ -180,16 +191,17 @@ namespace :gcc do
FileList['gcc/dg.exp', 'README.md'].each do |file|
link_frontend file, test_destination
end
- destination = GCC_TREE + 'gcc/testsuite/lib'
+ destination = GCC_TREE / 'gcc/testsuite/lib'
FileList['gcc/testlib/*'].each do |file|
- rm_f (destination + File.basename(file))
+ rm_f destination / File.basename(file)
link_frontend file, destination
end
end
desc 'Configure the bootstrap compiler'
- task configure: [HOST_GCC, HOST_INSTALL.to_path] do |t|
+ task configure: [GCC_HOST, GCC_HOST_INSTALL.to_path] do |t|
build_target = find_build_target GCC_VERSION
+ UI.step "Configuring bootstrap compiler for #{build_target.target}..."
configure_options = [
"--prefix=#{File.realpath t.prerequisites.last}",
'--enable-languages=c,c++,jit,elna',
@@ -208,25 +220,28 @@ namespace :gcc do
}
env['CFLAGS'] = env['CXXFLAGS'] = '-O0 -g -fPIC -I/opt/homebrew/opt/flex/include'
- configure = GCC_TREE.relative_path_from(HOST_GCC) + 'configure'
- sh env, configure.to_path, *configure_options, chdir: HOST_GCC
+ configure = GCC_TREE.relative_path_from(GCC_HOST) / 'configure'
+ sh env, configure.to_path, *configure_options, chdir: GCC_HOST
end
desc 'Make and install the bootstrap compiler'
task :make do
- sh 'make', '-j', Etc.nprocessors.to_s, chdir: HOST_GCC
- sh 'make', 'install', chdir: HOST_GCC
+ UI.step "Building bootstrap compiler (jobs: #{Etc.nprocessors})..."
+ sh 'make', '-j', Etc.nprocessors.to_s, chdir: GCC_HOST
+ sh 'make', 'install', chdir: GCC_HOST
end
desc 'Convert the testsuite into dejagnu format'
task :convert do
- destination = GCC_TREE + 'gcc/testsuite/elna.dg'
+ UI.step 'Converting testsuite to DejaGnu format...'
+ destination = GCC_TREE / 'gcc/testsuite/elna.dg'
destination.mkpath
source = Pathname.new 'testsuite'
# Regenerate the category directories from scratch: this removes
# converted tests whose sources are gone and adds new ones.
%w[compilable fail_compilation runnable].each do |category|
+ UI.debug "Converting #{category} tests..."
category_destination = destination + category
category_source = source + category
@@ -235,32 +250,8 @@ namespace :gcc do
category_source.each_child do |test_path|
test_target = category_destination + test_path.basename
-
- # Multi-module tests: directories containing a sut.elna (system under
- # test) and any helper files, compiled and linked together.
if test_path.directory?
- main = test_path + 'sut.elna'
- raise %(multi-module test directory \"#{test_path}\" must contain sut.elna) unless main
-
- test_target.mkdir
- modules = test_path.children - [main]
-
- modules.each do |extra|
- cp_r extra, test_target
- end
- extra_lines = ["(* { dg-additional-options \"-I#{test_target.expand_path}\" } *)"]
-
- # Only 'runnable' tests link the helper modules into an executable,
- # so only they need the helper sources compiled as separate
- # translation units via dg-additional-sources. Elna resolves imports
- # on its own, so passing it as an additional source there would add a
- # second positional.
- if category == 'runnable'
- extra_sources = test_target.glob("**/*.elna")
- .map { |extra| %("#{extra.relative_path_from test_target}") }
- extra_lines << "(* { dg-additional-sources #{extra_sources * ' '} } *)"
- end
- convert_test main, (test_target + 'sut.elna'), category, extra_lines
+ convert_multi_module_test test_path, test_target, category
else
convert_test test_path, test_target, category
end
@@ -270,25 +261,27 @@ namespace :gcc do
desc 'Run tests'
task check: 'gcc:convert' do
- log_file = Pathname.new(HOST_GCC) + 'gcc/testsuite/elna/elna.log'
-
- sh 'make', 'check-elna', chdir: File.join(HOST_GCC, 'gcc')
+ UI.step 'Running DejaGnu testsuite...'
+ log_file = Pathname.new(GCC_HOST) / 'gcc/testsuite/elna/elna.log'
- fail "\nSee #{log_file}." if log_file.file? and log_file.read =~ /^(FAIL|XPASS|UNRESOLVED|ERROR):/
+ sh 'make', 'check-elna', chdir: File.join(GCC_HOST, 'gcc')
+ UI.fatal "See #{log_file}." if log_file.file? && log_file.read =~ /^(FAIL|XPASS|UNRESOLVED|ERROR):/
end
desc 'Run clang-tidy'
task :tidy do
compile_db = Pathname.new 'compile_commands.json'
- raise "#{compile_db} is missing. Run: bear -- rake gcc:make" unless compile_db.exist?
+ UI.fatal "#{compile_db} is missing.", hint: 'Run: bear -- rake gcc:make' unless compile_db.exist?
+
sources = FileList['boot/*.cc', 'gcc/gcc/*.cc', 'include/elna/**/*.h']
.reject do |file|
['/elna1.', '/elna-spec.'].any? { |pattern| file.include? pattern }
end
+ UI.step "Running clang-tidy on #{sources.size} files..."
build_target = find_build_target GCC_VERSION
includes = ['.', build_target.target].collect do |inc|
- HOST_INSTALL + 'include/c++' + GCC_VERSION + inc
+ GCC_HOST_INSTALL / 'include/c++' / GCC_VERSION / inc
end
sh 'clang-tidy', '-p', compile_db.to_path, '--extra-arg=-w', '--warnings-as-errors=*',
@@ -298,7 +291,7 @@ namespace :gcc do
desc 'Build documentation'
task :doc do
- sh 'make', 'html', chdir: File.join(HOST_GCC, 'gcc')
+ sh 'make', 'html', chdir: File.join(GCC_HOST, 'gcc')
end
desc 'Run GCC linters and tests'
diff --git a/rakelib/ruby.rake b/rakelib/ruby.rake
new file mode 100644
index 0000000..c3db30a
--- /dev/null
+++ b/rakelib/ruby.rake
@@ -0,0 +1,11 @@
+# This Source Code Form is subject to the terms of the Mozilla Public License,
+# v. 2.0. If a copy of the MPL was not distributed with this file, You can
+# obtain one at https://mozilla.org/MPL/2.0/.
+# frozen_string_literal: true
+
+require 'rubocop/rake_task'
+
+namespace :ruby do
+ desc 'Run RuboCop'
+ RuboCop::RakeTask.new :lint
+end
diff --git a/rakelib/support/ui.rb b/rakelib/support/ui.rb
new file mode 100644
index 0000000..3120721
--- /dev/null
+++ b/rakelib/support/ui.rb
@@ -0,0 +1,25 @@
+# This Source Code Form is subject to the terms of the Mozilla Public License,
+# v. 2.0. If a copy of the MPL was not distributed with this file, You can
+# obtain one at https://mozilla.org/MPL/2.0/.
+# frozen_string_literal: true
+
+require 'term/ansicolor'
+
+# Terminal UI helpers for build milestones, debug logging, and operational errors.
+module UI
+ extend Term::ANSIColor
+
+ def self.step(message)
+ puts green(message)
+ end
+
+ def self.debug(message)
+ puts "#{dark(' ->')} #{dark(message)}" if Rake.verbose
+ end
+
+ def self.fatal(message, hint: nil)
+ output = red(message)
+ output += "\n#{bold(cyan('Hint:'))} #{hint}" if hint
+ abort output
+ end
+end
diff --git a/rakelib/treesitter.rake b/rakelib/treesitter.rake
index 7e48865..ca0c8d0 100644
--- a/rakelib/treesitter.rake
+++ b/rakelib/treesitter.rake
@@ -18,8 +18,8 @@ namespace :ts do
cp_r TREE_SITTER_TREE, TREE_SITTER_BUILD unless TREE_SITTER_BUILD.directory?
sh 'tree-sitter', 'generate',
- '--output', (TREE_SITTER_BUILD + 'src').to_path,
- (TREE_SITTER_TREE + 'grammar.js').to_path
+ '--output', (TREE_SITTER_BUILD / 'src').to_path,
+ (TREE_SITTER_TREE / 'grammar.js').to_path
build_test = TREE_SITTER_BUILD / 'test'
build_corpus = build_test / 'corpus'
@@ -44,7 +44,7 @@ namespace :ts do
File.open target, 'w' do |output|
output.write "==================\n"
- output.write(File.basename(test, '.elna') + "\n")
+ output.write "#{File.basename(test, '.elna')}\n"
output.write "==================\n\n"
output.write File.read(test)
output.write "\n---\n\n"
@@ -61,5 +61,4 @@ namespace :ts do
end
desc 'Build a tree-sitter parser'
-task ts: 'ts:generate'
-task ts: "#{TREE_SITTER_BUILD}/parser.so"
+task ts: ['ts:generate', "#{TREE_SITTER_BUILD}/parser.so"]