Compare commits

..
1 Commits
Author SHA1 Message Date
josh 6f9b21adb9 wip 2022-02-27 16:10:34 -05:00
79 changed files with 483 additions and 1621 deletions

No files matched your search

-38
View File
@@ -1,38 +0,0 @@
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
-51
View File
@@ -1,54 +1,3 @@
## 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
### New Features
- #171 - Place object files next to source files for source files in build directory
- #170 - Use top-level build directory as environment build directory for unnamed environments
- #167 - Add upgrading instructions
- #166 - Replace CFile builder with Yacc and Lex builders
### Fixes
- #172 - Fix configuration checks performed with ldc2 compiler
- #169 - Output a better error when pkg-config is not found
- #168 - Cannot output binary to an environment's build root with the same name as the top-level source directory
- #164 - Improve DSL method documentation
## v3.1.0
### New Features
- #162 - Improve configuration error messages
- #163 - Ruby 3.2 compatibility
### Fixes
- #161 - builder registered during build hooks should increase build step count
## v3.0.2
### Fixes
- #159 - Compiler check configure methods should respect :use flag
- #160 - Configure parameters should not be stored as unscoped construction variables
## v3.0.1
### Fixes
- #156 - Avoid running configure operation twice
- #157 - Load configure task arguments before early configure operations
- #158 - Do not configure for clean tasks when not yet configured
## v3.0.0
- #136 - Move rsconscache into build directory
+1 -1
View File
@@ -9,6 +9,6 @@ To run the rscons specs, the following commands must be available:
* g++
* clang++
* gdc
* ldc2
* ldc
* flex
* bison
-2
View File
@@ -1,10 +1,8 @@
source 'https://rubygems.org'
gem "base64"
gem "rspec"
gem "rake"
gem "simplecov", "~> 0.15.0"
gem "openssl"
if RbConfig::CONFIG["host"]["msys"]
gem "json", "2.1.0"
else
+18 -32
View File
@@ -1,53 +1,39 @@
GEM
remote: https://rubygems.org/
specs:
base64 (0.3.0)
date (3.5.1)
diff-lcs (1.6.2)
diff-lcs (1.4.4)
docile (1.1.5)
erb (6.0.1)
json (2.18.0)
openssl (4.0.0)
psych (5.3.1)
date
stringio
rake (13.3.1)
rdoc (7.1.0)
erb
psych (>= 4.0.0)
tsort
redcarpet (3.6.1)
rspec (3.13.2)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.6)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.5)
json (2.5.1)
rake (13.0.6)
rdoc (6.3.2)
redcarpet (3.5.1)
rspec (3.10.0)
rspec-core (~> 3.10.0)
rspec-expectations (~> 3.10.0)
rspec-mocks (~> 3.10.0)
rspec-core (3.10.1)
rspec-support (~> 3.10.0)
rspec-expectations (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.7)
rspec-support (~> 3.10.0)
rspec-mocks (3.10.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.6)
rspec-support (~> 3.10.0)
rspec-support (3.10.2)
simplecov (0.15.1)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
stringio (3.2.0)
syntax (1.2.2)
tsort (0.2.0)
yard (0.9.38)
yard (0.9.26)
PLATFORMS
ruby
x86-mingw32
DEPENDENCIES
base64
json
openssl
rake
rdoc
redcarpet
@@ -57,4 +43,4 @@ DEPENDENCIES
yard
BUNDLED WITH
2.6.2
2.1.4
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2013-2025 Josh Holtrop
Copyright (c) 2013-2022 Josh Holtrop
MIT License
+1 -1
View File
@@ -9,7 +9,7 @@ It supports the following features:
* multi-threaded job execution
* auto-configuration
* built-in builders for several common operations
* out-of-the-box support for Assembly, C, C++, D, and LLVM
* out-of-the-box support for C, C++, and D languages
* extensibility for other languages or custom builders
* compatible with Windows, Linux, OS X, and FreeBSD
* colorized output with build progress
+3 -4
View File
@@ -32,12 +32,11 @@ end
# useful for coverage information.
desc "Dist Specs"
task :dspec, [:example_string] => :build_dist do |task, args|
FileUtils.rm_rf("test")
FileUtils.mkdir_p("test")
FileUtils.cp("dist/rscons", "test/rscons.rb")
ENV["rscons_dist_specs"] = "1"
Rake::Task["spec"].execute(args)
ENV.delete("rscons_dist_specs")
ENV["dist_specs"] = "1"
Rake::Task["spec"].execute(args.example_string)
ENV.delete("dist_specs")
FileUtils.rm_f(Dir.glob(".rscons-*"))
end
-10
View File
@@ -1,10 +0,0 @@
# Upgrading
## v3.2.0
- Replace any calls to `env.CFile()` builder with `env.Lex()` or `env.Yacc()` as required.
## v3.0.0
- Move `build` block contents outside of `build` block and remove `build` call.
- Replace `Environment.new()` calls with `env()`.
+4
View File
@@ -0,0 +1,4 @@
env do |env|
env.CFile("lexer.c", "lexer.l")
env.CFile("parser.c", "parser.y")
end
@@ -0,0 +1,3 @@
env do |env|
env.CFile("file.c", "foo.bar")
end
File renamed without changes.
File renamed without changes.
+2 -2
View File
@@ -1,10 +1,10 @@
debug = env("dbg", echo: :command) do |env|
debug = env(echo: :command) do |env|
env['CFLAGS'] = '-O2'
env['CPPFLAGS'] = '-DSTRING="Debug Version"'
env.Program('program-debug.exe', Dir['src/*.c'])
end
release = debug.clone("rls") do |env|
release = debug.clone do |env|
env["CPPFLAGS"] = '-DSTRING="Release Version"'
env.Program('program-release.exe', Dir['src/*.c'])
end
+2 -2
View File
@@ -1,4 +1,4 @@
env1 = env("e1", echo: :command) do |env|
env1 = env(echo: :command) do |env|
env['CFLAGS'] = '-O2'
env.add_build_hook do |builder|
builder.vars['CPPFLAGS'] = '-DSTRING="Hello"'
@@ -9,6 +9,6 @@ env1 = env("e1", echo: :command) do |env|
env.Program('program.exe', Dir['src/*.c'])
end
env2 = env1.clone("e2") do |env|
env2 = env1.clone do |env|
env.Program('program2.exe', Dir['src/*.c'])
end
@@ -1,12 +0,0 @@
configure do
check_c_compiler "clang", use: "clang"
check_c_compiler
end
env "t1" do |env|
env.Program("test_gcc.exe", "simple.c")
end
env "t2", use: "clang" do |env|
env.Program("test_clang.exe", "simple.c")
end
@@ -1,5 +0,0 @@
ENV["PATH"] = ""
configure do
check_cfg package: "mypackage"
end
@@ -1,12 +0,0 @@
configure do
check_cxx_compiler "clang++", use: "clang"
check_cxx_compiler
end
env "t1" do |env|
env.Program("test_gcc.exe", "simple.cc")
end
env "t2", use: "clang" do |env|
env.Program("test_clang.exe", "simple.cc")
end
@@ -1,3 +1,3 @@
configure do
check_d_compiler "gdc", "ldc2", "ldc"
check_d_compiler "gdc", "ldc2"
end
@@ -1,12 +0,0 @@
configure do
check_d_compiler "ldc2", use: "ldc2"
check_d_compiler
end
env "t1" do |env|
env.Program("test_gcc.exe", "simple.d")
end
env "t2", use: "ldc2" do |env|
env.Program("test_ldc2.exe", "simple.d")
end
@@ -1,8 +0,0 @@
configure do
check_d_compiler "ldc2"
check_lib "z"
end
env(echo: :command) do |env|
env.Program("simple.exe", "simple.d")
end
@@ -1,6 +0,0 @@
configure do
check_c_compiler
end
env do |env|
puts "Prefix is #{Task["configure"]["prefix"]}"
end
-6
View File
@@ -1,6 +0,0 @@
#include <iostream>
int main(int argc, char *argv[])
{
std::cout << "Hi" << std::endl;
}
-7
View File
@@ -1,7 +0,0 @@
import std.stdio;
int main()
{
writeln("Hello");
return 0;
}
+1 -2
View File
@@ -3,6 +3,5 @@ configure do
end
env(echo: :command) do |env|
env["D_IMPORT_PATH"] << "src"
env.Program("hello-d.exe", glob("src/*.d"))
env.Program("hello-d.exe", glob("*.d"))
end
+1 -2
View File
@@ -3,6 +3,5 @@ configure do
end
env(echo: :command) do |env|
env["D_IMPORT_PATH"] << "src"
env.Program("hello-d.exe", glob("src/*.d"))
env.Program("hello-d.exe", glob("*.d"))
end
+2 -3
View File
@@ -1,6 +1,5 @@
env(echo: :command) do |env|
env["LD_LIBRARY_PATH"] << "src"
env.Object("main.o", "src/main.d")
env.Object("mod.o", "src/mod.d")
env.Object("main.o", "main.d")
env.Object("mod.o", "mod.d")
env.Program("hello-d.exe", ["main.o", "mod.o"])
end
File renamed without changes.
File renamed without changes.
-4
View File
@@ -1,4 +0,0 @@
env do |env|
env.Lex("lexer.c", "lexer.l")
env.Yacc("parser.c", "parser.y")
end
+2 -5
View File
@@ -1,7 +1,4 @@
env(echo: :command) do |env|
env["LIBS"] << "mylib"
env["LIBPATH"] << "."
env.Program("library.exe", "one.c")
env.depends("library.exe", "libmylib.a")
env.Library("libmylib.a", ["two.c", "three.c"], "CPPFLAGS" => ["-Dmake_lib"])
env.Program('library.exe', ['lib.a', 'three.c'])
env.Library("lib.a", ['one.c', 'two.c'], 'CPPFLAGS' => ['-Dmake_lib'])
end
+2 -5
View File
@@ -1,11 +1,8 @@
#include <stdio.h>
void two();
void three();
#ifdef make_lib
int main(int argc, char *argv[])
{
two();
printf("Library\n");
three();
}
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
env(echo: :command) do |env|
env["ARCMD"] = %w[ar rc ${_TARGET} ${_SOURCES}]
env["ARCMD"] = %w[ar rcf ${_TARGET} ${_SOURCES}]
env.Library("lib.a", glob("*.c"))
end
-3
View File
@@ -1,3 +0,0 @@
void three(void)
{
}
-3
View File
@@ -1,3 +0,0 @@
void two(void)
{
}
-4
View File
@@ -1,4 +0,0 @@
env do |env|
env["LLVMAS_FLAGS"] += %w[-Wno-override-module]
env.Program("llvmtest.exe", %w[main.c one.ll])
end
-8
View File
@@ -1,8 +0,0 @@
configure do
check_c_compiler "clang"
end
env do |env|
env["LLVMAS_FLAGS"] += %w[-Wno-override-module]
env.Program("llvmtest.exe", %w[one.ll two.ll main2.c], direct: true)
end
-6
View File
@@ -1,6 +0,0 @@
extern int one(void);
int main(int argc, char * argv[])
{
return one();
}
-9
View File
@@ -1,9 +0,0 @@
extern int one(void);
extern int two(void);
int main(int argc, char * argv[])
{
one();
two();
return 0;
}
-9
View File
@@ -1,9 +0,0 @@
@str = private unnamed_addr constant [12 x i8] c"hello world\00"
declare i32 @puts(ptr nocapture) nounwind
define i32 @one()
{
call i32 @puts(ptr @str)
ret i32 0
}
-9
View File
@@ -1,9 +0,0 @@
@str = private unnamed_addr constant [12 x i8] c"hello again\00"
declare i32 @puts(ptr nocapture) nounwind
define i32 @two()
{
call i32 @puts(ptr @str)
ret i32 0
}
@@ -1,13 +0,0 @@
env("e", echo: :command) do |env|
source_file = "#{env.build_root}/src/foo.c"
FileUtils.mkdir_p(File.dirname(source_file))
File.open(source_file, "w") do |fh|
fh.puts(<<-EOF)
int main()
{
return 29;
}
EOF
end
env.Program("foo.exe", source_file)
end
@@ -1,7 +1,7 @@
class MyObject < Rscons::Builder
def run(options)
if @builder
if File.exist?(@target)
if File.exists?(@target)
true
else
false
-7
View File
@@ -1,7 +0,0 @@
env do |env|
env.Program('simple.exe', Dir['*.c'])
end
clean do
puts "custom clean action"
end
-5
View File
@@ -1,5 +0,0 @@
default do
env do |env|
env.Program('simple.exe', Dir['*.c'])
end
end
-1
View File
@@ -1,6 +1,5 @@
env(echo: :command) do |env|
env["LD"] = "gcc"
mkdir_p("libdir")
env["LIBPATH"] += ["libdir"]
env.Program('simple.exe', Dir['*.c'])
end
+1 -1
View File
@@ -4,7 +4,7 @@ class TestBuilder < Rscons::Builder
true
else
if @target == "two"
return false unless File.exist?("one")
return false unless File.exists?("one")
end
wait_time = @env.expand_varref("${wait_time}", @vars)
@command = ["ruby", "-e", "require 'fileutils'; sleep #{wait_time}; FileUtils.touch('#{@target}');"]
+1 -1
View File
@@ -3,5 +3,5 @@ env do |env|
env["CFLAGS"] += %w[-S]
env.Object("one.ssss", "one.c", "CPPFLAGS" => ["-DONE"])
env.Object("two.sss", "two.c")
env.Program("two_sources.exe", %w[one.ssss two.sss], "ASFLAGS" => env["ASFLAGS"] + %w[-x assembler-with-cpp])
env.Program("two_sources.exe", %w[one.ssss two.sss], "ASFLAGS" => env["ASFLAGS"] + %w[-x assembler])
end
-3
View File
@@ -1,6 +1,3 @@
#ifdef ONE
#error ONE should not be defined
#endif
void two(void)
{
}
@@ -1,4 +0,0 @@
env "src" do |env|
env["CPPPATH"] += glob("src/**")
env.Program("^/src", glob("src/**/*.c"))
end
-15
View File
@@ -1,15 +0,0 @@
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
@@ -1,13 +0,0 @@
variant "debug"
variant "release"
with_variants do
env do |env|
if variant("debug")
env["CPPDEFINES"] << "DEBUG"
else
env["CPPDEFINES"] << "NDEBUG"
end
env.Program("^/prog.exe", "prog.c")
end
end
+35 -203
View File
@@ -6,7 +6,7 @@ It supports the following features:
* multi-threaded job execution
* auto-configuration
* built-in builders for several common operations
* out-of-the-box support for Assembly, C, C++, D, and LLVM
* out-of-the-box support for C, C++, and D languages
* extensibility for other languages or custom builders
* compatible with Windows, Linux, OS X, and FreeBSD
* colorized output with build progress
@@ -265,17 +265,21 @@ which they were added.
Example:
```ruby
proj_env = env do |env|
env.Program("^/proj.elf", glob("src/**/*.c"))
task "build" do
env do |env|
env.Program("^^/proj.elf", glob("src/**/*.c"))
end
end
task "flash" do
sh "nrfjprog", "-f", "NRF52", "--program", proj_env.expand("^/proj.elf")
task "flash", deps: "build" do
sh "nrfjprog", "-f", "NRF52", "--program", env.expand("^^/proj.elf")
end
```
In this example, the `flash` task would first build the proj.elf target and
then flash it to target with the nrfjprog program.
In this example, the `flash` task depends on the `build` task.
So if the project had not yet been built, and the user executes
`./rscons flash`, the project would first be built and then flashed to the
target.
If the `task` method is called again with the name of an already existing task,
the task is not overwritten, but rather modified.
@@ -283,34 +287,6 @@ Any newly specified dependencies are added to the current dependencies.
Any action block is appended to the task's list of action blocks to execute
when the task is executed.
For example, with the `Rsconscript`:
```ruby
task "a" do
puts "A"
end
task "b" do
puts "B"
end
task "c", depends: "a" do
puts "C1"
end
task "c", depends: "b" do
puts "C2"
end
```
The following behavior is observed:
$ ./rscons c
A
B
C1
C2
Note that for a simple project, the build script may not need to define any
tasks at all and could just make use of the Rscons built-in default task (see
${#Default Task}).
@@ -402,7 +378,7 @@ argument (task name) automatically filled in by the shortcut method.
For example:
```ruby
default depends: "unpack_compiler" do
default deps: "unpack_compiler" do
puts "default task"
end
```
@@ -410,7 +386,7 @@ end
is equivalent to:
```ruby
task "default", depends: "unpack_compiler" do
task "default", deps: "unpack_compiler" do
puts "default task"
end
```
@@ -470,9 +446,6 @@ end
See ${#Configuring the Project} for more details on how to make use of the
configuration functionality that Rscons provides.
Configure blocks must be defined in the Rsconscript file before any
environments are created.
####> Default Task
The `default` task is special in that Rscons will execute it if no other task
@@ -487,11 +460,11 @@ task "build" do
...
end
task "flash", depends: "build" do
task "flash" do
...
end
default depends: "build"
default deps: "build"
```
Then when the user runs `./rscons` the "build" task will be executed.
@@ -814,9 +787,7 @@ Building target files is accomplished by using Environments.
Environments can be created at the top level of the build script, or from
within a task action block.
Environments are created with the
[`env`](../yard/Rscons/Script/GlobalDsl.html#env-instance_method) build script
method.
Environments are created with the `env` build script method.
Here is an example build script that creates an Environment and registers a
Program build target:
@@ -892,7 +863,7 @@ It also instructs the linker to link against the `m` library.
* uppercase strings - the default construction variables that Rscons uses
* strings beginning with "_" - set and used internally by builders
* lowercase strings with a ":" as "#{task_name}:#{parameter_name}" - set to task parameter values
* strings with a ":" as "#{task_name}:#{parameter_name}" - set to task parameter values
* symbols, lowercase strings - reserved as user-defined construction variables
###> Builders
@@ -925,11 +896,11 @@ There are several default builders that are built-in to Rscons:
* `Command`, which executes a user-defined command to produce the target.
* `Copy`, which copies files or directories to a specified destination.
* `CFile`, which builds a C or C++ source file from a lex or yacc input file.
* `Directory`, which creates a directory.
* `Disassemble`, which disassembles an object file to a disassembly listing.
* `Install`, which installs files or directories to a specified destination.
* `InstallDirectory`, which creates a directory in an install destination.
* `Lex`, which builds a source file from a lex input file.
* `Library`, which collects object files into a static library archive file.
* `Object`, which compiles source files to produce an object file.
* `Preprocess`, which invokes the C/C++ preprocessor on a source file.
@@ -939,7 +910,6 @@ There are several default builders that are built-in to Rscons:
* `SharedObject`, which compiles source files to produce an object file, in a
way that is able to be used to create a shared library.
* `Size`, which runs the 'size' utility on an executable file.
* `Yacc`, which builds a source file from a yacc input file.
####> The Command Builder
@@ -966,6 +936,17 @@ The `Command` builder supports the following construction variables:
`CMD_STDOUT` is expanded for variable references, so the token `${_TARGET}`
can be used, for example.
####> The CFile Builder
```ruby
env.CFile(target, source)
# Example
env.CFile("^/parser/parser.c", "parser.y")
```
The `CFile` builder will generate a C or C++ source file from a lex (.l, .ll)
or yacc (.y, .yy) input file.
####> The Copy Builder
```ruby
@@ -1038,17 +1019,6 @@ the `InstallDirectory` builder.
The `uninstall` task removes targets created by the `InstallDirectory` builder
but not by the `Directory` builder.
####> The Lex Builder
```ruby
env.Lex(target, source)
# Example
env.Lex("^/lexer.c", "lexer.l")
```
The `Lex` builder will generate a source file from a lex (.l, .ll)
input file.
####> The Library Builder
```ruby
@@ -1179,17 +1149,6 @@ stores its output in the target file.
The size executable can be specified with the `SIZE` construction variable,
and flags can be specified with `SIZEFLAGS`.
####> The Yacc Builder
```ruby
env.Yacc(target, source)
# Example
env.Yacc("^/parser.c", "parser.y")
```
The `Yacc` builder will generate a source file from a yacc (.y, .yy)
input file.
###> Phony Targets
Rscons supports phony build targets.
@@ -1308,10 +1267,10 @@ It iterates through each enabled variant and calls the given block.
In this example, the block would be called twice, once with the "kde" variant
active, and the second time with the "gnome" variant active.
Each `env` method call creates an Environment, so two environments are created.
Each `env()` call creates an Environment, so two environments are created.
When an Environment is created within a `with_variants` block, the
Environment's build directory name has the active variant(s) keys appended to
the given Environment name, and separated by a "-".
Environment's name has the active variant(s) appended to the given Environment
name (if any), and separated by a "-".
In this example, a "prog-kde" Environment would be created with build root
build/prog-kde and -DKDE would be passed to the compiler when compiling each
@@ -1320,29 +1279,6 @@ Next a "prog-gnome" Environment would be created with build root
build/prog-gnome and -DGNOME would be passed to the compiler when compiling
the sources.
The key for a variant is the variant's name by default but can be overridden by
passing a `:key` value to the `variant` method.
A `nil` value for the `:key` parameter will omit that variant from appearing
in the environment's build directory name.
For example:
```ruby
variant "debug"
variant "release", key: nil
with_variants do
env "prog" do |env|
end
end
```
In this example, one "prog" environment will be created for the "debug" variant
with the build directory "prog-debug", and another "prog" environment will be
created for the "release" variant with the build directory "prog".
The build directory for the release variant of the "prog" environment is just
"prog" instead of "prog-release" because the key for the "release" variant is
set to `nil`.
Variants are enabled by default, but can be disabled by passing a `false` value
to the `:default` option of the `variant` method.
For example:
@@ -1475,22 +1411,9 @@ Example use:
```ruby
default do
download "https://ftp.gnu.org/gnu/gcc/gcc-#{gcc_version}/gcc-#{gcc_version}.tar.xz",
"#{build_dir}/gcc-#{gcc_version}.tar.xz",
sha256_sum: gcc_checksum
end
```
The `download` method downloads the file specified by the URL in the first
parameter, and writes it to the local file specified by the second parameter.
If the `:sha256sum` option is given, this causes two changes to the default
behavior:
* If Rscons finds the local file and it already has this checksum, then the
file will not be downloaded again.
* After downloading, Rscons verifies that the checksum matches what is given
and exits with an error if it does not.
###> PATH Management
`rscons` provides methods for management of the `PATH` environment variable.
@@ -1617,8 +1540,8 @@ end
The `Object` and `SharedObject` builders that ship with Rscons have an API that
allows the user to register extra languages that can be suppored by the
builders.
In fact, the built-in support for assembly, C, C++, D, and LLVM compilation
all make use of this built-in API.
In fact, the built-in support for assembly, C, C++, and D compilation all make
use of this built-in API.
To see an example of how this API is used, see the
`lib/rscons/builders/lang/*.rb` files in the Rscons source repository.
For example, here is how the C++ language is registered:
@@ -1927,15 +1850,6 @@ env do |env|
end
```
### Example: Building a Program from C and LLVM Sources
```ruby
env do |env|
env["CFLAGS"] << "-Wall"
env.Program("program", glob("src/**/*.{c,ll}"))
end
```
### Example: Cloning an Environment
```ruby
@@ -2003,89 +1917,7 @@ end
```ruby
env do |env|
env.Yacc("^/parser.tab.cc", "parser.yy")
end
```
### Example: GCC Cross Compiler
```ruby
binutils_version = "2.35"
binutils_checksum = "1b11659fb49e20e18db460d44485f09442c8c56d5df165de9461eb09c8302f85"
gcc_version = "10.2.0"
gcc_checksum = "b8dd4368bb9c7f0b98188317ee0254dd8cc99d1e3a18d0ff146c855fe16c1d8c"
install_path = File.expand_path("i686-elf-gcc")
target = "i686-elf"
path_prepend "#{install_path}/bin"
configure do
check_c_compiler "gcc"
check_program "make"
check_program "bison"
check_program "flex"
check_program "texi2any", on_fail: "Install the texinfo package"
check_program "wget"
check_lib "gmp", on_fail: "Install the libgmp-dev package"
check_lib "mpc", on_fail: "Install the libmpc-dev package"
check_lib "mpfr", on_fail: "Install the libmpfr-dev package"
end
default do
unless Dir.exist?(install_path)
# Download archives.
download "https://ftp.gnu.org/gnu/binutils/binutils-#{binutils_version}.tar.xz",
"#{build_dir}/binutils-#{binutils_version}.tar.xz",
sha256sum: binutils_checksum
download "https://ftp.gnu.org/gnu/gcc/gcc-#{gcc_version}/gcc-#{gcc_version}.tar.xz",
"#{build_dir}/gcc-#{gcc_version}.tar.xz",
sha256sum: gcc_checksum
# Extract archives.
sh "tar", "xJf", "binutils-#{binutils_version}.tar.xz",
chdir: build_dir
sh "tar", "xJf", "gcc-#{gcc_version}.tar.xz",
chdir: build_dir
# Build binutils.
rm_rf "#{build_dir}/build-binutils"
mkdir_p "#{build_dir}/build-binutils"
cd "#{build_dir}/build-binutils" do
sh %W[../binutils-#{binutils_version}/configure
--target=#{target} --prefix=#{install_path} --with-sysroot --disable-nls
--disable-werror]
sh "make"
sh "make install"
end
# Build gcc.
rm_rf "#{build_dir}/build-gcc"
mkdir_p "#{build_dir}/build-gcc"
cd "#{build_dir}/build-gcc" do
sh %W[../gcc-#{gcc_version}/configure
--target=#{target} --prefix=#{install_path} --disable-nls
--enable-languages=c,c++ --without-headers]
sh "make all-gcc"
sh "make all-target-libgcc"
sh "make install-gcc"
sh "make install-target-libgcc"
end
end
end
clean do
rm_f "#{build_dir}/binutils-#{binutils_version}.tar.xz"
rm_rf "#{build_dir}/binutils-#{binutils_version}"
rm_rf "#{build_dir}/build-binutils"
rm_f "#{build_dir}/gcc-#{gcc_version}.tar.xz"
rm_rf "#{build_dir}/gcc-#{gcc_version}"
rm_rf "#{build_dir}/build-gcc"
end
distclean do
rm_rf install_path
env.CFile("^/parser.tab.cc", "parser.yy")
end
```
+2 -16
View File
@@ -23,23 +23,20 @@ module Rscons
# Names of the default builders which will be added to all newly created
# {Environment} objects.
DEFAULT_BUILDERS = [
:Barrier,
:CFile,
:Command,
:Copy,
:Directory,
:Disassemble,
:Install,
:InstallDirectory,
:Lex,
:Library,
:Object,
:Precompile,
:Preprocess,
:Program,
:SharedLibrary,
:SharedObject,
:Size,
:Yacc,
]
# Class to represent a fatal error during an Rscons operation.
@@ -68,13 +65,6 @@ module Rscons
target.is_a?(Symbol)
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 [Array<String>] The shell and flag.
@@ -145,29 +135,25 @@ require_relative "rscons/builders/mixins/object_deps"
require_relative "rscons/builders/mixins/program"
# default builders
require_relative "rscons/builders/barrier"
require_relative "rscons/builders/cfile"
require_relative "rscons/builders/command"
require_relative "rscons/builders/copy"
require_relative "rscons/builders/directory"
require_relative "rscons/builders/disassemble"
require_relative "rscons/builders/lex"
require_relative "rscons/builders/library"
require_relative "rscons/builders/object"
require_relative "rscons/builders/precompile"
require_relative "rscons/builders/preprocess"
require_relative "rscons/builders/program"
require_relative "rscons/builders/shared_library"
require_relative "rscons/builders/shared_object"
require_relative "rscons/builders/simple_builder"
require_relative "rscons/builders/size"
require_relative "rscons/builders/yacc"
# language support
require_relative "rscons/builders/lang/asm"
require_relative "rscons/builders/lang/c"
require_relative "rscons/builders/lang/cxx"
require_relative "rscons/builders/lang/d"
require_relative "rscons/builders/lang/llvm_asm"
# Unbuffer $stdout
$stdout.sync = true
+23 -64
View File
@@ -42,16 +42,6 @@ module Rscons
@variant_groups = []
end
# Return if Rscons is in the task execution phase.
#
# @api private
#
# @return [Boolean]
# If Rscons is in the task execution phase.
def task_execution_phase?
@task_execution_phase
end
# Run the application.
#
# Execute user-specified tasks.
@@ -73,7 +63,6 @@ module Rscons
# Process exit code (0 on success).
def run(rsconscript, tasks_and_params, show_tasks, all_tasks, enabled_variants)
Cache.instance["failed_commands"] = []
@tasks_and_params = tasks_and_params
@enabled_variants = enabled_variants
if enabled_variants == "" && !tasks_and_params.include?("configure")
if cache_enabled_variants = Cache.instance["configuration_data"]["enabled_variants"]
@@ -81,16 +70,13 @@ module Rscons
end
end
@script = Script.new
if should_load_script
@script.load(rsconscript)
enable_variants
end
@script.load(rsconscript)
enable_variants
if show_tasks
show_script_tasks(all_tasks)
return 0
end
apply_task_params(false)
@task_execution_phase = true
apply_task_params(tasks_and_params)
if tasks_and_params.empty?
check_process_environments
if Task.tasks["default"]
@@ -172,8 +158,8 @@ module Rscons
def distclean
cache = Cache.instance
clean
cache.clear
FileUtils.rm_rf(@build_dir)
cache.clear
end
# Check if the project needs to be configured.
@@ -182,7 +168,6 @@ module Rscons
#
# @return [void]
def check_configure
apply_task_params(true)
enable_variants
unless Cache.instance["configuration_data"]["configured"]
if @script.autoconf
@@ -209,20 +194,20 @@ module Rscons
#
# @api private
#
# @param options [Hash]
# Options.
#
# @return [void]
def configure
unless @_configured
@_configured = true
co = ConfigureOp.new(@script)
begin
@script.configure(co)
rescue RsconsError => e
co.close(false)
raise e
end
Cache.instance["configuration_data"]["enabled_variants"] = @enabled_variants
co.close(true)
co = ConfigureOp.new(@script)
begin
@script.configure(co)
rescue RsconsError => e
co.close(false)
raise e
end
Cache.instance["configuration_data"]["enabled_variants"] = @enabled_variants
co.close(true)
end
# Remove installed files.
@@ -237,7 +222,7 @@ module Rscons
cache = Cache.instance
cache.targets(true).each do |target|
cache.remove_target(target)
next unless File.exist?(target)
next unless File.exists?(target)
puts "Removing #{target}" if verbose
FileUtils.rm_f(target)
end
@@ -258,14 +243,6 @@ module Rscons
#
# @param name [String]
# Variant name.
# @param options [Hash]
# Optional parameters.
# @option options [String] :default
# Whether the variant is enabled by default (default: true).
# @option options [String] :key
# Variant key, used to name an Environment's build directory. If nil,
# this variant will not contribute to the Environment's build directory
# name.
def variant(name, options = {})
if @active_variants
!!@active_variants.find {|variant| variant[:name] == name}
@@ -302,15 +279,6 @@ module Rscons
end
# Create a variant group.
#
# @overload variant_group(name, options = {})
# @param name [String]
# Variant group name (optional).
# @param options [Hash]
# Optional variant group parameters.
# @overload variant_group(options = {})
# @param options [Hash]
# Optional variant group parameters.
def variant_group(*args, &block)
if args.first.is_a?(String)
name = args.slice!(0)
@@ -399,27 +367,18 @@ module Rscons
end
end
def apply_task_params(only_configure)
@tasks_and_params.each do |task_name, task_params|
unless only_configure && task_name != "configure"
task_params.each do |param_name, param_value|
if param = Task[task_name].params[param_name]
Task[task_name].set_param_value(param_name, param_value)
else
raise RsconsError.new("Unknown parameter #{param_name.inspect} for task #{task_name}")
end
def apply_task_params(tasks_and_params)
tasks_and_params.each do |task_name, task_params|
task_params.each do |param_name, param_value|
if param = Task[task_name].params[param_name]
Task[task_name].set_param_value(param_name, param_value)
else
raise RsconsError.new("Unknown parameter #{param_name.inspect} for task #{task_name}")
end
end
end
end
def should_load_script
return true if @tasks_and_params.empty?
return true if Cache.instance["configuration_data"]["configured"]
return false if (@tasks_and_params.keys - %w[distclean clean uninstall]).empty?
true
end
end
end
+3 -10
View File
@@ -27,9 +27,8 @@ module Rscons
# env.Directory("dest")
# env.Install("dest", "bin")
# env.Install("dest", "share")
target = Util.absolute_path(builder.target)
self[target] ||= []
self[target] << builder
self[builder.target] ||= []
self[builder.target] << builder
end
# Return the number of remaining build steps.
@@ -38,7 +37,7 @@ module Rscons
# The number of remaining build steps.
def build_steps_remaining
self.reduce(0) do |result, (target, builders)|
result + builders.count {|b| !b.is_a?(Rscons::Builders::Barrier)}
result + builders.size
end
end
@@ -56,14 +55,9 @@ module Rscons
def get_next_builder_to_run(targets_still_building)
to_build = self.find do |target, builders|
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
# build.
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) ||
self.include?(dep) ||
@side_effects.include?(dep))
@@ -72,7 +66,6 @@ module Rscons
if to_build
target, builders = *to_build
puts "Selecting #{target.inspect} to build"
builder = builders.first
if builders.size > 1
builders.slice!(0)
-15
View File
@@ -1,15 +0,0 @@
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
+35
View File
@@ -0,0 +1,35 @@
module Rscons
module Builders
# Build a C or C++ source file given a lex (.l, .ll) or yacc (.y, .yy)
# input file.
#
# Examples::
# env.CFile("parser.tab.cc", "parser.yy")
# env.CFile("lex.yy.cc", "parser.ll")
class CFile < Builder
# Run the builder to produce a build target.
def run(options)
if @command
finalize_command
else
@vars["_TARGET"] = @target
@vars["_SOURCES"] = @sources
case
when @sources.first.end_with?(*@env.expand_varref("${LEXSUFFIX}"))
cmd = "LEX"
message = "Generating lexer"
when @sources.first.end_with?(*@env.expand_varref("${YACCSUFFIX}"))
cmd = "YACC"
message = "Generating parser"
else
raise "Unknown source file #{@sources.first.inspect} for CFile builder"
end
command = @env.build_command("${#{cmd}_CMD}", @vars)
standard_command("#{message} from <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
end
end
end
end
end
+4 -4
View File
@@ -14,14 +14,14 @@ module Rscons
# Run the builder to produce a build target.
def run(options)
target_is_dir = (@sources.length > 1) ||
Dir.exist?(@sources.first) ||
Dir.exist?(@target)
Dir.exists?(@sources.first) ||
Dir.exists?(@target)
outdir = target_is_dir ? @target : File.dirname(@target)
# Collect the list of files to copy over.
file_map = {}
if target_is_dir
@sources.each do |src|
if Dir.exist? src
if Dir.exists? src
Dir.glob("#{src}/**/*", File::FNM_DOTMATCH).select do |f|
File.file?(f)
end.each do |subfile|
@@ -50,7 +50,7 @@ module Rscons
end
@cache.register_build(dest, :Copy, [src], @env, install: @install_builder)
end
(target_is_dir ? Dir.exist?(@target) : File.exist?(@target)) ? true : false
(target_is_dir ? Dir.exists?(@target) : File.exists?(@target)) ? true : false
end
end
+1 -1
View File
@@ -14,7 +14,7 @@ module Rscons
def run(options)
if File.directory?(@target)
true
elsif File.exist?(@target)
elsif File.exists?(@target)
Ansi.write($stderr, :red, "Error: `#{@target}' already exists and is not a directory", :reset, "\n")
false
else
-10
View File
@@ -1,10 +0,0 @@
Rscons::Builders::Object.register(
command: "${LLVMAS_CMD}",
direct_command: "${LLVMAS_CMD:direct}",
suffix: "${LLVMAS_SUFFIX}",
short_description: "Assembling")
Rscons::Builders::SharedObject.register(
command: "${LLVMAS_CMD}",
direct_command: "${LLVMAS_CMD:direct}",
suffix: "${LLVMAS_SUFFIX}",
short_description: "Assembling")
-24
View File
@@ -1,24 +0,0 @@
module Rscons
module Builders
# Build a source file given a lex input file.
#
# Examples::
# env.Lex("lex.c", "parser.l")
# env.Lex("lex.cc", "parser.ll")
class Lex < Builder
# Run the builder to produce a build target.
def run(options)
if @command
finalize_command
else
@vars["_TARGET"] = @target
@vars["_SOURCES"] = @sources
command = @env.build_command("${LEX_CMD}", @vars)
standard_command("Generating lexer source from <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
end
end
end
end
end
+1 -1
View File
@@ -8,7 +8,7 @@ module Rscons
# dependency file.
def finalize_command_with_depfile
deps = @sources
if File.exist?(@vars["_DEPFILE"])
if File.exists?(@vars["_DEPFILE"])
deps += Util.parse_dependency_file(@vars["_DEPFILE"])
end
@cache.register_build(@target, @command, deps.uniq, @env)
+1 -6
View File
@@ -15,16 +15,11 @@ module Rscons
# List of paths to the object or static library dependencies.
def register_object_deps(builder_class)
suffixes = @env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], @vars)
barrier_target = @env.setup_precompile(@sources)
@sources.map do |source|
if source.end_with?(*suffixes)
source
else
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
@env.register_dependency_build(@target, source, suffixes.first, @vars, builder_class)
end
end
end
-29
View File
@@ -1,29 +0,0 @@
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
-24
View File
@@ -1,24 +0,0 @@
module Rscons
module Builders
# Build a source file given a yacc input file.
#
# Examples::
# env.Yacc("parser.c", "parser.y")
# env.Yacc("parser.cc", "parser.yy")
class Yacc < Builder
# Run the builder to produce a build target.
def run(options)
if @command
finalize_command
else
@vars["_TARGET"] = @target
@vars["_SOURCES"] = @sources
command = @env.build_command("${YACC_CMD}", @vars)
standard_command("Generating parser source from <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
end
end
end
end
end
+19 -34
View File
@@ -101,7 +101,6 @@ module Rscons
#
# @return [void]
def write
return unless Dir.exist?(File.dirname(cache_file))
@cache["version"] = VERSION
File.open(cache_file, "w") do |fh|
fh.puts(JSON.dump(@cache))
@@ -142,16 +141,14 @@ module Rscons
# - each cached dependency file's current checksum matches the checksum
# stored in the cache file
def up_to_date?(targets, command, deps, env, options = {})
deps.map! {|dep| Util.absolute_path(dep)}
Array(targets).each do |target|
target = Util.absolute_path(target)
cache_key = get_cache_key(target)
unless Rscons.phony_target?(target)
# target file must exist on disk
unless File.exist?(target)
if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Cache: up_to_date?: Target #{target} needs rebuilding because it does not exist on disk"
unless File.exists?(target)
if options[:debug]
puts "Target #{target} needs rebuilding because it does not exist on disk"
end
return false
end
@@ -159,8 +156,8 @@ module Rscons
# target must be registered in the cache
unless @cache["targets"].has_key?(cache_key)
if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Cache: up_to_date?: Target #{target} needs rebuilding because there is no cached build information for it"
if options[:debug]
puts "Target #{target} needs rebuilding because there is no cached build information for it"
end
return false
end
@@ -168,8 +165,8 @@ module Rscons
unless Rscons.phony_target?(target)
# target must have the same checksum as when it was built last
unless @cache["targets"][cache_key]["checksum"] == lookup_checksum(target)
if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Cache: up_to_date?: Target #{target} needs rebuilding because it has been changed on disk since being built last"
if options[:debug]
puts "Target #{target} needs rebuilding because it has been changed on disk since being built last"
end
return false
end
@@ -177,8 +174,8 @@ module Rscons
# command used to build target must be identical
unless @cache["targets"][cache_key]["command"] == Digest::MD5.hexdigest(command.inspect)
if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Cache: up_to_date?: Target #{target} needs rebuilding because the command used to build it has changed"
if options[:debug]
puts "Target #{target} needs rebuilding because the command used to build it has changed"
end
return false
end
@@ -188,16 +185,16 @@ module Rscons
if options[:strict_deps]
# depedencies passed in must exactly equal those in the cache
unless deps == cached_deps_fnames
if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
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"
if options[: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"
end
return false
end
else
# all dependencies passed in must exist in cache (but cache may have more)
unless (Set.new(deps) - Set.new(cached_deps_fnames)).empty?
if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Cache: up_to_date?: Target #{target} needs rebuilding because there are new dependencies"
if options[:debug]
puts "Target #{target} needs rebuilding because there are new dependencies"
end
return false
end
@@ -205,12 +202,11 @@ module Rscons
# set of user dependencies must match
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_fnames = cached_user_deps.map { |dc| dc["fname"] }
unless user_deps == cached_user_deps_fnames
if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Cache: up_to_date?: Target #{target} needs rebuilding because the set of user-specified dependency files has changed"
if options[:debug]
puts "Target #{target} needs rebuilding because the set of user-specified dependency files has changed"
end
return false
end
@@ -218,14 +214,12 @@ module Rscons
# all cached dependencies must have their checksums match
(cached_deps + cached_user_deps).each do |dep_cache|
unless dep_cache["checksum"] == lookup_checksum(dep_cache["fname"])
if options[:debug] || ENV["RSCONS_CACHE_DEBUG"]
puts "Cache: up_to_date?: Target #{target} needs rebuilding because dependency file #{dep_cache["fname"]} has changed"
if options[:debug]
puts "Target #{target} needs rebuilding because dependency file #{dep_cache["fname"]} has changed"
end
return false
end
end
puts "Cache: up_to_date?: Target #{target} is up to date" if ENV["RSCONS_CACHE_DEBUG"]
end
true
@@ -252,26 +246,22 @@ module Rscons
# @return [void]
def register_build(targets, command, deps, env, options = {})
Array(targets).each do |target|
target = Util.absolute_path(target)
target_checksum =
if options[:side_effect] or Rscons.phony_target?(target)
""
else
calculate_checksum(target)
end
puts "Cache: register_build(#{target}, #{target_checksum})"
@cache["targets"][get_cache_key(target)] = {
"command" => Digest::MD5.hexdigest(command.inspect),
"checksum" => target_checksum,
"deps" => deps.map do |dep|
dep = Util.absolute_path(dep)
{
"fname" => dep,
"checksum" => lookup_checksum(dep),
}
end,
"user_deps" => (env.get_user_deps(target) || []).map do |dep|
dep = Util.absolute_path(dep)
{
"fname" => dep,
"checksum" => lookup_checksum(dep),
@@ -316,7 +306,7 @@ module Rscons
parts.each_index do |i|
next if parts[i] == ""
subpath = File.join(*parts[0, i + 1])
unless File.exist?(subpath)
unless File.exists?(subpath)
FileUtils.mkdir_p(subpath)
@cache["directories"][subpath] = !!options[:install]
end
@@ -390,8 +380,6 @@ module Rscons
#
# @return [String] The file's checksum.
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)
end
@@ -401,10 +389,7 @@ module Rscons
#
# @return [String] The file's checksum.
def calculate_checksum(file)
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
@lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file, mode: "rb")) rescue ""
end
end
+2 -2
View File
@@ -118,13 +118,13 @@ module Rscons
# Find the build script.
if rsconscript
unless File.exist?(rsconscript)
unless File.exists?(rsconscript)
$stderr.puts "Cannot read #{rsconscript}"
return 1
end
else
rsconscript = DEFAULT_RSCONSCRIPTS.find do |f|
File.exist?(f)
File.exists?(f)
end
end
+29 -75
View File
@@ -1,6 +1,5 @@
require "fileutils"
require "open3"
require "set"
module Rscons
# Class to manage a configure operation.
@@ -11,11 +10,9 @@ module Rscons
# @param script [Script]
# Build script.
def initialize(script)
@tested_compilers = {}
@work_dir = "#{Rscons.application.build_dir}/_configure"
FileUtils.mkdir_p(@work_dir)
@log_file_name = "#{@work_dir}/config.log"
@log_fh = File.open(@log_file_name, "wb")
@log_fh = File.open("#{@work_dir}/config.log", "wb")
cache = Cache.instance
cache["failed_commands"] = []
cache["configuration_data"] = {}
@@ -26,11 +23,14 @@ module Rscons
$stdout.puts "Configuring project..."
end
end
vars = {}
Task["configure"].params.each do |name, param|
unless Rscons.application.silent_configure
Ansi.write($stdout, "Setting #{name}... ", :green, param.value, :reset, "\n")
end
vars[name] = param.value
end
store_merge(vars)
end
# Close the log file handle.
@@ -65,15 +65,9 @@ module Rscons
ccc = %w[gcc clang]
end
cc = ccc.find do |cc|
test_c_compiler(cc, options)
test_c_compiler(cc)
end
if cc
@tested_compilers["c"] ||= Set.new
@tested_compilers["c"] << cc
end
complete(cc ? 0 : 1, options.merge(
success_message: cc,
fail_message: "not found (checked #{ccc.join(", ")})"))
complete(cc ? 0 : 1, options.merge(success_message: cc))
end
# Check for a working C++ compiler.
@@ -93,15 +87,9 @@ module Rscons
ccc = %w[g++ clang++]
end
cc = ccc.find do |cc|
test_cxx_compiler(cc, options)
test_cxx_compiler(cc)
end
if cc
@tested_compilers["cxx"] ||= Set.new
@tested_compilers["cxx"] << cc
end
complete(cc ? 0 : 1, options.merge(
success_message: cc,
fail_message: "not found (checked #{ccc.join(", ")})"))
complete(cc ? 0 : 1, options.merge(success_message: cc))
end
# Check for a working D compiler.
@@ -118,18 +106,12 @@ module Rscons
end
if cdc.empty?
# Default D compiler search array.
cdc = %w[gdc ldc2 ldc]
cdc = %w[gdc ldc2]
end
dc = cdc.find do |dc|
test_d_compiler(dc, options)
test_d_compiler(dc)
end
if dc
@tested_compilers["d"] ||= Set.new
@tested_compilers["d"] << dc
end
complete(dc ? 0 : 1, options.merge(
success_message: dc,
fail_message: "not found (checked #{cdc.join(", ")})"))
complete(dc ? 0 : 1, options.merge(success_message: dc))
end
# Check for a package or configure program output.
@@ -139,12 +121,7 @@ module Rscons
elsif program = options[:program]
Ansi.write($stdout, "Checking '", :cyan, program, :reset, "'... ")
end
unless program
program = "pkg-config"
unless Util.find_executable(program)
raise RsconsError.new("Error: executable '#{program}' not found")
end
end
program ||= "pkg-config"
args = options[:args] || %w[--cflags --libs]
command = [program, *args, package].compact
stdout, _, status = log_and_test_command(command)
@@ -266,36 +243,17 @@ module Rscons
def check_lib(lib, options = {})
check_libpath = [nil] + (options[:check_libpath] || [])
Ansi.write($stdout, "Checking for library '", :cyan, lib, :reset, "'... ")
if @tested_compilers["d"]
source_file = "#{@work_dir}/cfgtest.d"
File.open(source_file, "wb") do |fh|
fh.puts <<-EOF
int main() {
return 0;
}
EOF
end
else
source_file = "#{@work_dir}/cfgtest.c"
File.open(source_file, "wb") do |fh|
fh.puts <<-EOF
int main(int argc, char * argv[]) {
return 0;
}
EOF
end
end
ld = "${CC}"
%w[d cxx c].each do |language|
if @tested_compilers[language]
ld = @tested_compilers[language].first
break
end
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
fh.puts <<-EOF
int main(int argc, char * argv[]) {
return 0;
}
EOF
end
vars = {
"LD" => ld,
"LD" => "${CC}",
"LIBS" => [lib],
"_SOURCES" => source_file,
"_SOURCES" => "#{@work_dir}/cfgtest.c",
"_TARGET" => "#{@work_dir}/cfgtest.exe",
}
status = 1
@@ -420,8 +378,6 @@ module Rscons
# A define to set (in CPPDEFINES) if the requested item is found.
# @option options [String] :success_message
# Message to print on success (default "found").
# @option options [String] :fail_message
# Message to print on failure (default "not found").
def complete(status, options)
success_message = options[:success_message] || "found"
fail_message = options[:fail_message] || "not found"
@@ -445,7 +401,7 @@ module Rscons
options[:on_fail].call
end
if should_fail
raise RsconsError.new("Configuration failed; log file written to #{@log_file_name}")
raise RsconsError.new("Configuration failed")
end
end
end
@@ -459,7 +415,7 @@ module Rscons
#
# @return [Boolean]
# Whether the C compiler tested successfully.
def test_c_compiler(cc, options)
def test_c_compiler(cc)
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
fh.puts <<-EOF
int fun(int val) {
@@ -471,7 +427,7 @@ module Rscons
merge = {"CC" => cc}
_, _, status = log_and_test_command(command)
if status == 0
store_merge(merge, options)
store_merge(merge)
true
end
end
@@ -483,7 +439,7 @@ module Rscons
#
# @return [Boolean]
# Whether the C++ compiler tested successfully.
def test_cxx_compiler(cc, options)
def test_cxx_compiler(cc)
File.open("#{@work_dir}/cfgtest.cxx", "wb") do |fh|
fh.puts <<-EOF
template<typename T>
@@ -496,7 +452,7 @@ module Rscons
merge = {"CXX" => cc}
_, _, status = log_and_test_command(command)
if status == 0
store_merge(merge, options)
store_merge(merge)
true
end
end
@@ -508,7 +464,7 @@ module Rscons
#
# @return [Boolean]
# Whether the D compiler tested successfully.
def test_d_compiler(dc, options)
def test_d_compiler(dc)
File.open("#{@work_dir}/cfgtest.d", "wb") do |fh|
fh.puts <<-EOF
import core.math;
@@ -529,17 +485,15 @@ module Rscons
env = BasicEnvironment.new
merge = {
"DC" => dc,
"DC:-o" => "-of",
"LD:-o" => "-of",
"LIBDIRPREFIX" => "-L-L",
"LIBLINKPREFIX" => "-L-l",
"DCCMD" => env["DCCMD"].map {|e| e.sub(/^-o$/, "-of")},
"LDCMD" => env["LDCMD"].map {|e| e.sub(/^-o$/, "-of")},
"DDEPGEN" => ["-deps=${_DEPFILE}"],
}
merge["OBJSUFFIX"] = [ldc_objsuffix]
end
_, _, status = log_and_test_command(command)
if status == 0
store_merge(merge, options)
store_merge(merge)
true
end
end
+5 -12
View File
@@ -35,24 +35,21 @@ module Rscons
"CXXFLAGS" => [],
"CXXSUFFIX" => %w[.cc .cpp .cxx .C],
"DC" => "gdc",
"DC:-o" => "-o",
"DCCMD" => %w[${DC} -c ${DC:-o} ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${_SOURCES}],
"DCCMD:direct" => %w[${DC} ${DC:-o} ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
"DCCMD" => %w[${DC} -c -o ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${_SOURCES}],
"DCCMD:direct" => %w[${DC} -o ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
"DDEPGEN" => %w[-MMD -MF ${_DEPFILE}],
"DEPFILESUFFIX" => ".mf",
"DFLAGS" => [],
"DISASM_CMD" => %w[${OBJDUMP} ${DISASM_FLAGS} ${_SOURCES}],
"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],
"D_IMPORT_PATH" => [],
"INCPREFIX" => "-I",
"LD" => nil,
"LD:-o" => "-o",
"LDCMD" => %w[${LD} ${LD:-o} ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
"LDCMD" => %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
"LDFLAGS" => [],
"LEX" => "flex",
"LEXSUFFIX" => %w[.l .ll],
"LEX_CMD" => %w[${LEX} ${LEX_FLAGS} -o ${_TARGET} ${_SOURCES}],
"LEX_FLAGS" => [],
"LIBDIRPREFIX" => "-L",
@@ -60,11 +57,6 @@ module Rscons
"LIBPATH" => [],
"LIBS" => [],
"LIBSUFFIX" => ".a",
"LLVMAS" => "clang",
"LLVMAS_CMD" => %w[${LLVMAS} -c -o ${_TARGET} ${LLVMAS_FLAGS} ${_SOURCES}],
"LLVMAS_CMD:direct" => %w[${LLVMAS} -o ${_TARGET} ${LLVMAS_FLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
"LLVMAS_FLAGS" => [],
"LLVMAS_SUFFIX" => ".ll",
"OBJDUMP" => "objdump",
"OBJSUFFIX" => %w[.o],
"PROGSUFFIX" => on_windows ? ".exe" : "",
@@ -92,6 +84,7 @@ module Rscons
"SIZECMD" => %w[${SIZE} ${SIZEFLAGS} ${_SOURCES}],
"SIZEFLAGS" => [],
"YACC" => "bison",
"YACCSUFFIX" => %w[.y .yy],
"YACC_CMD" => %w[${YACC} ${YACC_FLAGS} -o ${_TARGET} ${_SOURCES}],
"YACC_FLAGS" => %w[-d],
}
+37 -93
View File
@@ -72,21 +72,35 @@ module Rscons
attr_reader :name
# Create an Environment object.
#
# @overload initialize(name, options)
# @overload initialize(options)
#
# @param name [String]
# Environment name. This determines the folder name used to store all
# environment build files under the top-level build directory.
# @param options [Hash]
# @option options [Symbol] :echo
# :command, :short, or :off (default :short)
# @option options [Boolean] :exclude_builders
# Whether to omit adding default builders (default false)
# @option options [String, Array<String>] :use
# Use flag(s). If specified, any configuration flags which were saved
# with a corresponding `:use` value will be applied to this Environment.
#
# If a block is given, the Environment object is yielded to the block and
# when the block returns, the {#process} method is automatically called.
def initialize(*args, &block)
@id = self.class.get_id
if args.first.is_a?(String)
base_name = args.slice!(0)
else
base_name = "e.#{@id}"
end
variant_keys = (Rscons.application.active_variants || []).map do |variant|
variant[:key]
end.compact
if args.first.is_a?(String)
base_name = args.slice!(0)
@name = [base_name, *variant_keys].join("-")
@build_root = "#{Rscons.application.build_dir}/#{@name}"
else
if variant_keys.size > 0
raise RsconsError.new("Error: an Environment with active variants must be given a name")
end
@build_root = Rscons.application.build_dir
end
@name = [base_name, *variant_keys].join("-")
options = args.first || {}
unless Cache.instance["configuration_data"]["configured"]
raise "Project must be configured before creating an Environment"
@@ -118,8 +132,8 @@ module Rscons
else
:short
end
@build_root = "#{Rscons.application.build_dir}/#{@name}"
@n_threads = Rscons.application.n_threads
@build_steps = 0
self.class.register(self)
if block
Environment.running_environment = self
@@ -280,26 +294,7 @@ module Rscons
if extra_path = builder_class.extra_path
extra_path = "/#{extra_path}"
end
source_fname = source_fname.gsub("\\", "/")
if extra_path.nil? && source_fname.start_with?("#{@build_root}/")
# If the source file is in the environment's build directory and no
# builder "extra path" is present, then just place the output file
# next to the source file.
"#{source_fname}#{suffix}"
else
"#{@build_root}/o#{extra_path}/#{Util.make_relative_path("#{source_fname}#{suffix}")}"
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)}"
"#{@build_root}#{extra_path}/#{Util.make_relative_path("#{source_fname}#{suffix}")}".gsub("\\", "/")
end
# Build all build targets specified in the Environment.
@@ -382,7 +377,6 @@ module Rscons
@builder_sets << build_builder_set
end
@builder_sets.last << builder
@build_steps += 1
@build_targets[target] = builder
builder
else
@@ -400,9 +394,7 @@ module Rscons
if target.is_a?(Builder)
target = target.target
end
unless Rscons.phony_target?(target)
target = Util.absolute_path(expand(target))
end
target = expand(target.to_s)
user_deps = user_deps.map do |ud|
if ud.is_a?(Builder)
ud = ud.target
@@ -410,11 +402,7 @@ module Rscons
expand(ud)
end
@user_deps[target] ||= []
user_deps.each do |ud|
unless @user_deps[target].include?(ud)
@user_deps[target] << Util.absolute_path(ud)
end
end
@user_deps[target] = (@user_deps[target] + user_deps).uniq
build_after(target, user_deps)
end
@@ -445,16 +433,14 @@ module Rscons
targets = Array(targets)
prerequisites = Array(prerequisites)
targets.each do |target|
unless Rscons.phony_target?(target)
target = Util.absolute_path(expand(target))
end
target = expand(target)
@registered_build_dependencies[target] ||= Set.new
prerequisites.each do |prerequisite|
if prerequisite.is_a?(Builder)
prerequisite = prerequisite.target
end
prerequisite = expand(prerequisite)
@registered_build_dependencies[target] << Util.absolute_path(prerequisite)
@registered_build_dependencies[target] << prerequisite
end
end
end
@@ -469,7 +455,7 @@ module Rscons
#
# @return [void]
def produces(target, *side_effects)
target = Util.absolute_path(expand(target))
target = expand(target)
@builder_sets.reverse.each do |builder_set|
if builders = builder_set[target]
builders.last.produces(*side_effects)
@@ -615,42 +601,6 @@ module Rscons
@builder_sets << build_builder_set
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
# Build a BuilderSet.
@@ -678,9 +628,7 @@ module Rscons
#
# @return [void]
def run_builder(builder)
unless builder.is_a?(Rscons::Builders::Barrier)
builder.build_step ||= get_next_build_step
end
builder.build_step ||= get_next_build_step
case result = builder.run({})
when Array
result.each do |waititem|
@@ -706,10 +654,8 @@ module Rscons
Cache.instance.register_build(side_effect, nil, [], self, side_effect: true)
@side_effects.delete(side_effect)
end
unless builder.is_a?(Rscons::Builders::Barrier)
@build_hooks[:post].each do |build_hook_block|
build_hook_block.call(builder)
end
@build_hooks[:post].each do |build_hook_block|
build_hook_block.call(builder)
end
process_remove_wait(builder)
else
@@ -781,15 +727,13 @@ module Rscons
# If no builder was found to run yet and there are threads available, try
# to get a runnable builder from the builder set.
targets_still_building = @threads.reduce([]) do |result, (thread, obj)|
result << Util.absolute_path(builder_for_thread(thread).target)
result << builder_for_thread(thread).target
end
if @builder_sets.size > 0
if builder = @builder_sets[0].get_next_builder_to_run(targets_still_building)
builder.vars = @varset.merge(builder.vars)
unless builder.is_a?(Rscons::Builders::Barrier)
@build_hooks[:pre].each do |build_hook_block|
build_hook_block.call(builder)
end
@build_hooks[:pre].each do |build_hook_block|
build_hook_block.call(builder)
end
return run_builder(builder)
end
+16 -107
View File
@@ -34,7 +34,15 @@ module Rscons
#
# @return [Array<String>] Paths matching the specified pattern(s).
def glob(*patterns)
Util.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
# Download a file.
@@ -94,49 +102,9 @@ module Rscons
end
# Create an environment.
#
# @overload env(name, options)
# @param name [String]
# Environment name. This determines the folder name used to store all
# environment build files under the top-level build directory.
# @param options [Hash]
# @option options [Symbol] :echo
# :command, :short, or :off (default :short)
# @option options [Boolean] :exclude_builders
# Whether to omit adding default builders (default false)
# @option options [String, Array<String>] :use
# Use flag(s). If specified, any configuration flags which were saved
# with a corresponding `:use` value will be applied to this
# Environment.
#
# @overload env(options)
# @param options [Hash]
# @option options [Symbol] :echo
# :command, :short, or :off (default :short)
# @option options [Boolean] :exclude_builders
# Whether to omit adding default builders (default false)
# @option options [String, Array<String>] :use
# Use flag(s). If specified, any configuration flags which were saved
# with a corresponding `:use` value will be applied to this
# Environment.
#
# If a block is given it is immediately executed and passed the newly
# created Environment object as an argument.
# If the Environment is created in task context, the +process+ method is
# immediately called.
# Otherwise, the Environment is not processed until the task execution
# phase.
#
# @yield [env]
# @yieldparam env [Environment]
# The created environment.
def env(*args, &block)
Rscons.application.check_configure
e = Environment.new(*args, &block)
if Rscons.application.task_execution_phase?
e.process
end
e
Environment.new(*args, &block)
end
# Construct a task parameter.
@@ -281,80 +249,27 @@ module Rscons
end
# Create or modify a task.
#
# @overload task(name, options = {}, &block)
# @param name [String]
# Task name.
# @param options [Hash]
# Optional task attributes.
# @option options [Boolean] :autoconf
# Whether to automatically configure before running this task
# (default: true).
# @option options [String] :desc
# Description for the task.
# @option options [Array<String>] :depends
# Dependencies of the task.
# @option options [Array<Task::Param>] :params
# Task parameter definitions.
#
# The action block given will be invoked by Rscons when the task
# executes. It will be passed two arguments:
# 1) The Task object.
# 2) A Hash of task parameter names and values.
def task(*args, &block)
Util.task(*args, &block)
end
# Define a variant, or within a with_variants block, query if it is
# active.
#
# @param name [String]
# Variant name.
# @param options [Hash]
# Optional parameters.
# @option options [String] :default
# Whether the variant is enabled by default (default: true).
# @option options [String] :key
# Variant key, used to name an Environment's build directory. If nil,
# this variant will not contribute to the Environment's build directory
# name.
def variant(name, options = {})
Rscons.application.variant(name, options)
def variant(*args)
Rscons.application.variant(*args)
end
# Check if a variant is enabled.
#
# This can be used, for example, in a configuration block to omit or
# include configuration checks based on which variants have been
# configured.
#
# @param variant_name [String]
# Variant name.
#
# @return [Boolean]
# Whether the requested variant is enabled.
def variant_enabled?(variant_name)
Rscons.application.variant_enabled?(variant_name)
def variant_enabled?(*args)
Rscons.application.variant_enabled?(*args)
end
# Create a variant group.
#
# @overload variant_group(name, options = {})
# @param name [String]
# Variant group name (optional).
# @param options [Hash]
# Optional variant group parameters.
# @overload variant_group(options = {})
# @param options [Hash]
# Optional variant group parameters.
def variant_group(*args, &block)
Rscons.application.variant_group(*args, &block)
end
# Iterate through enabled variants.
#
# The given block is called for each combination of enabled variants
# across the defined variant groups.
# Iterate through variants.
def with_variants(&block)
Rscons.application.enable_variants
Rscons.application.with_variants(&block)
@@ -394,17 +309,11 @@ module Rscons
# Top-level DSL available to the Rsconscript.
class TopLevelDsl < GlobalDsl
# Set the project name.
#
# @param project_name [String]
# Project name.
def project_name(project_name)
@script.project_name = project_name
end
# Set whether to automatically configure (default true).
#
# @param autoconf [Boolean]
# Whether to automatically configure.
# Whether to automatically configure (default true).
def autoconf(autoconf)
@script.autoconf = autoconf
end
-105
View File
@@ -16,42 +16,6 @@ module Rscons
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.
#
# @param message [String]
@@ -156,29 +120,6 @@ module Rscons
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.
#
# @return [String]
@@ -200,52 +141,6 @@ module Rscons
result
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.
#
# @param path [String]
+1 -1
View File
@@ -1,4 +1,4 @@
module Rscons
# Project version.
VERSION = "3.3.0"
VERSION = "2.3.0"
end
+13 -54
View File
@@ -1,10 +1,7 @@
#!/usr/bin/env ruby
require "base64"
require "digest/md5"
require "fileutils"
require "stringio"
require "zlib"
require "digest/md5"
if File.read("lib/rscons/version.rb") =~ /VERSION = "(.+)"/
VERSION = $1
@@ -25,7 +22,7 @@ combine_files = lambda do |file|
require_name = $1
if require_name =~ %r{^#{PROG_NAME}(?:/.*)?$}
path = "#{LIB_DIR}/#{require_name}.rb"
if File.exist?(path)
if File.exists?(path)
unless files_processed[path]
files_processed[path] = true
combine_files[path]
@@ -63,23 +60,13 @@ combined_file.each do |line|
end
end
license = File.read("LICENSE.txt").gsub(/^(.*?)$/) do |line|
if line.size > 0
"# #{line}"
else
"#"
end
end
license = File.read("LICENSE.txt").gsub(/^/, "# ")
require "zlib"
require "base64"
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_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
hash = Digest::MD5.hexdigest(encoded_compressed_script)
FileUtils.rm_rf(DIST)
FileUtils.mkdir_p(DIST)
@@ -89,53 +76,25 @@ File.open("#{DIST}/#{PROG_NAME}", "wb", 0755) do |fh|
#{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")
unless File.exist?(script)
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/m
unless File.exists?(script)
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
require "zlib"
require "base64"
encoded_compressed = $1
compressed = base64_decode(encoded_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)
unescaped_compressed = Base64.decode64(encoded_compressed)
inflated = Zlib::Inflate.inflate(unescaped_compressed)
File.open(script, "wb") do |fh|
fh.write(inflated)
end
else
raise "Error expanding rscons executable"
raise "Could not decompress."
end
end
load script
if __FILE__ == $0
Rscons::Cli.new.run(ARGV)
end
#==>
#{commented_encoded_compressed_script}
#==>#{encoded_compressed_script}
EOF
end
+1 -1
View File
@@ -99,7 +99,7 @@ class Generator
end
template = File.read("rb/assets/user_guide.html.erb")
erb = ERB.new(template, trim_mode: "<>")
erb = ERB.new(template, nil, "<>")
if multi_page
@pages.each_with_index do |page, page_index|
+192 -370
View File
File diff suppressed because it is too large. Load diff
+8 -8
View File
@@ -17,14 +17,14 @@ module Rscons
it "makes directories and records any created in the cache" do
_cache = {}
cache = build_from(_cache)
expect(File).to receive(:exist?).with("one").and_return(true)
expect(File).to receive(:exist?).with("one/two").and_return(false)
expect(File).to receive(:exists?).with("one").and_return(true)
expect(File).to receive(:exists?).with("one/two").and_return(false)
expect(FileUtils).to receive(:mkdir_p).with("one/two")
expect(File).to receive(:exist?).with("one/two/three").and_return(false)
expect(File).to receive(:exists?).with("one/two/three").and_return(false)
expect(FileUtils).to receive(:mkdir_p).with("one/two/three")
expect(File).to receive(:exist?).with("one").and_return(true)
expect(File).to receive(:exist?).with("one/two").and_return(true)
expect(File).to receive(:exist?).with("one/two/four").and_return(false)
expect(File).to receive(:exists?).with("one").and_return(true)
expect(File).to receive(:exists?).with("one/two").and_return(true)
expect(File).to receive(:exists?).with("one/two/four").and_return(false)
expect(FileUtils).to receive(:mkdir_p).with("one/two/four")
cache.mkdir_p("one/two/three")
cache.mkdir_p("one\\two\\four")
@@ -34,8 +34,8 @@ module Rscons
it "handles absolute paths" do
_cache = {}
cache = build_from(_cache)
expect(File).to receive(:exist?).with("/one").and_return(true)
expect(File).to receive(:exist?).with("/one/two").and_return(false)
expect(File).to receive(:exists?).with("/one").and_return(true)
expect(File).to receive(:exists?).with("/one/two").and_return(false)
expect(FileUtils).to receive(:mkdir_p).with("/one/two")
cache.mkdir_p("/one/two")
expect(cache.directories(false)).to eq ["/one/two"]
+7 -2
View File
@@ -1,4 +1,4 @@
if ENV["rscons_dist_specs"]
if ENV["dist_specs"]
require_relative "../test/rscons"
else
require "simplecov"
@@ -11,7 +11,12 @@ else
else
command_name "RSpec"
end
add_filter "test/rscons.rb"
if ENV["dist_specs"]
add_filter "/bin/"
add_filter "/lib/"
else
add_filter "test/rscons.rb"
end
project_name "Rscons"
merge_timeout 3600
end