Compare commits

..
4 Commits
65 changed files with 410 additions and 1457 deletions

No files matched your search

-43
View File
@@ -1,45 +1,3 @@
## v2.3.0
### New Features
- #125 - Support subsidiary Rsconscript files
- #126 - Add PATH manipulation methods
### Fixes
- #121 - env.depends() does not work with built-root-relative "^/" paths
- #130 - Document -f command line option
- #133 - Clarify failed command error message indicating to run -F
- #134 - Document CMD_STDOUT variable for Command builder
- #135 - Write dependency file to build directory when user invokes Object builder directly
- #141 - Document phony targets
## v2.2.0
### New Features
- #120 - improve support for MSYS2
- #119 - add failure messages for failed configuration checks
- #118 - compiler checks should support cross-compilers and freestanding compilers
## v2.1.0
### New Features
- #117 - ruby 2.7 compatibility
## v2.0.2
### Fixes
- #113 - distinguish object files built from multiple sources with the same base name but different extensions
## v2.0.1
### Fixes
- #112 - Install builder cannot replace a currently executing binary on Linux
## v2.0.0 ## v2.0.0
- convert rscons from a Ruby gem to a standalone script - convert rscons from a Ruby gem to a standalone script
@@ -74,7 +32,6 @@
- various performance improvements - various performance improvements
- wrote a new user guide - wrote a new user guide
- added new website ([https://holtrop.github.io/rscons/](https://holtrop.github.io/rscons/)) - added new website ([https://holtrop.github.io/rscons/](https://holtrop.github.io/rscons/))
- added new logo
## v1.17.0 ## v1.17.0
-14
View File
@@ -1,14 +0,0 @@
# Developing
# Specs
To run the rscons specs, the following commands must be available:
* gcc
* clang
* g++
* clang++
* gdc
* ldc
* flex
* bison
+6 -10
View File
@@ -1,14 +1,10 @@
source 'https://rubygems.org' source 'https://rubygems.org'
gem "json"
gem "rspec" gem "rspec"
gem "rake" gem "rake"
gem "simplecov", "~> 0.15.0" gem "simplecov"
if RbConfig::CONFIG["host"]["msys"] gem "yard"
gem "json", "2.1.0" gem "rdoc"
else gem "redcarpet"
gem "json" gem "syntax"
gem "yard"
gem "rdoc"
gem "redcarpet"
gem "syntax"
end
+21 -21
View File
@@ -1,32 +1,32 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
diff-lcs (1.4.4) diff-lcs (1.3)
docile (1.1.5) docile (1.3.2)
json (2.5.1) json (2.2.0)
rake (13.0.6) rake (12.3.2)
rdoc (6.3.2) rdoc (6.1.1)
redcarpet (3.5.1) redcarpet (3.4.0)
rspec (3.10.0) rspec (3.8.0)
rspec-core (~> 3.10.0) rspec-core (~> 3.8.0)
rspec-expectations (~> 3.10.0) rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.10.0) rspec-mocks (~> 3.8.0)
rspec-core (3.10.1) rspec-core (3.8.2)
rspec-support (~> 3.10.0) rspec-support (~> 3.8.0)
rspec-expectations (3.10.1) rspec-expectations (3.8.4)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0) rspec-support (~> 3.8.0)
rspec-mocks (3.10.2) rspec-mocks (3.8.1)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0) rspec-support (~> 3.8.0)
rspec-support (3.10.2) rspec-support (3.8.2)
simplecov (0.15.1) simplecov (0.15.0)
docile (~> 1.1.0) docile (~> 1.1.0)
json (>= 1.8, < 3) json (>= 1.8, < 3)
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.2) simplecov-html (0.10.2)
syntax (1.2.2) syntax (1.2.2)
yard (0.9.26) yard (0.9.20)
PLATFORMS PLATFORMS
ruby ruby
@@ -38,9 +38,9 @@ DEPENDENCIES
rdoc rdoc
redcarpet redcarpet
rspec rspec
simplecov (~> 0.15.0) simplecov
syntax syntax
yard yard
BUNDLED WITH BUNDLED WITH
2.1.4 1.17.3
-2
View File
@@ -1,7 +1,5 @@
# Rscons # Rscons
![rscons logo](img/rscons_logo_1000.png)
Rscons (https://github.com/holtrop/rscons) is an open-source build system Rscons (https://github.com/holtrop/rscons) is an open-source build system
for developers. for developers.
+9 -24
View File
@@ -6,27 +6,24 @@ rescue Bundler::BundlerError => e
end end
require "rspec/core/rake_task" require "rspec/core/rake_task"
require "yard"
require "rake/clean" require "rake/clean"
require "fileutils" require "fileutils"
CLEAN.include %w[build_test_run .yardoc yard coverage test] CLEAN.include %w[build_test_run .yardoc yard coverage test]
CLOBBER.include %w[dist gen large_project pkg] CLOBBER.include %w[dist pkg]
task :build_dist do task :build_dist do
sh "ruby rb/build_dist.rb" sh "ruby rb/build_dist.rb"
end end
RSpec::Core::RakeTask.new(:spec, :example_string) do |task, args| RSpec::Core::RakeTask.new(:spec, :example_string) do |task, args|
ENV["specs"] = "1"
if args.example_string if args.example_string
ENV["partial_specs"] = "1" ENV["partial_specs"] = "1"
task.rspec_opts = %W[-e "#{args.example_string}" -f documentation] task.rspec_opts = %W[-e "#{args.example_string}" -f documentation]
end end
end end
task :spec => :build_dist task :spec => :build_dist
task :spec do
ENV.delete("specs")
end
# dspec task is useful to test the distributable release script, but is not # dspec task is useful to test the distributable release script, but is not
# useful for coverage information. # useful for coverage information.
@@ -35,11 +32,16 @@ task :dspec, [:example_string] => :build_dist do |task, args|
FileUtils.mkdir_p("test") FileUtils.mkdir_p("test")
FileUtils.cp("dist/rscons", "test/rscons.rb") FileUtils.cp("dist/rscons", "test/rscons.rb")
ENV["dist_specs"] = "1" ENV["dist_specs"] = "1"
Rake::Task["spec"].execute(args.example_string) Rake::Task["spec"].invoke(args.example_string)
ENV.delete("dist_specs") ENV.delete("dist_specs")
FileUtils.rm_f(Dir.glob(".rscons-*")) FileUtils.rm_f(Dir.glob(".rscons-*"))
end end
YARD::Rake::YardocTask.new do |yard|
yard.files = ['lib/**/*.rb']
yard.options = ["-ogen/yard"]
end
task :gen_large_project, [:size] => :build_dist do |task, args| task :gen_large_project, [:size] => :build_dist do |task, args|
size = (args.size || 10000).to_i size = (args.size || 10000).to_i
FileUtils.rm_rf("large_project") FileUtils.rm_rf("large_project")
@@ -86,25 +88,8 @@ EOF
FileUtils.cp("dist/rscons", "large_project") FileUtils.cp("dist/rscons", "large_project")
end end
unless RbConfig::CONFIG["host"]["msys"] task :user_guide do
require "yard"
YARD::Rake::YardocTask.new do |yard|
yard.files = ['lib/**/*.rb']
yard.options = ["-ogen/yard"]
end
desc "Build user guide"
task :user_guide do
system("ruby", "-Ilib", "rb/gen_user_guide.rb") system("ruby", "-Ilib", "rb/gen_user_guide.rb")
end
end end
task :default => :spec task :default => :spec
task :all => [
:build_dist,
:spec,
:dspec,
:yard,
:user_guide,
]
@@ -1,5 +1,4 @@
configure do configure do
check_d_compiler
check_d_import "std.stdio", check_d_import_path: ["./usr1"] check_d_import "std.stdio", check_d_import_path: ["./usr1"]
check_d_import "frobulous", check_d_import_path: ["./usr2"] check_d_import "frobulous", check_d_import_path: ["./usr2"]
end end
@@ -1,4 +1,3 @@
configure do configure do
check_d_compiler
check_d_import "std.stdio" check_d_import "std.stdio"
end end
@@ -17,10 +17,6 @@ configure do
end end
op.complete(status, success_message: "good!", fail_message: fail_message, fail: should_fail) op.complete(status, success_message: "good!", fail_message: fail_message, fail: should_fail)
end end
custom_check("Checking sed -E flag") do |op|
stdout, stderr, status = op.log_and_test_command(%w[sed -E -e s/ab+/rep/], stdin: "abbbc")
op.complete(stdout =~ /repc/ ? 0 : 1, success_message: "good", fail_message: "fail")
end
end end
build do build do
-5
View File
@@ -1,5 +0,0 @@
configure do
check_c_compiler "foo123c", fail: false, on_fail: "Install the foo123 package"
check_d_compiler "foo123d", fail: false
check_cxx_compiler "foo123cxx", on_fail: lambda {puts "Install the foo123cxx package"}
end
+2 -3
View File
@@ -6,8 +6,7 @@ build do
"CMD_DESC" => "Generating") "CMD_DESC" => "Generating")
env["build_root"] = env.build_root env["build_root"] = env.build_root
env["inc_c"] = "inc.c" env["inc_c"] = "inc.c"
env.Object("program.o", "program.c") env.build_after("${build_root}/program.o", "${inc_c}")
env.build_after("program.o", "${inc_c}") env.Program("program.exe", ["program.c", "inc.c"])
env.Program("program.exe", ["program.o", "inc.c"])
end end
end end
+2 -3
View File
@@ -4,9 +4,8 @@ build do
env["inc_h"] = "inc.h" env["inc_h"] = "inc.h"
env.Copy("copy_inc.h", "${inc_h}") env.Copy("copy_inc.h", "${inc_h}")
env.depends("program.o", "${inc_h}") env.depends("${build_root}/program.o", "${inc_h}")
env.Object("program.o", "program.c") env.Program("program.exe", ["program.c", "inc.c"])
env.Program("program.exe", ["program.o", "inc.c"])
inc_c = env.Command("inc.c", inc_c = env.Command("inc.c",
[], [],
+2 -3
View File
@@ -4,9 +4,8 @@ build do
env["inc_h"] = "inc.h" env["inc_h"] = "inc.h"
env.Copy("copy_inc.h", "${inc_h}") env.Copy("copy_inc.h", "${inc_h}")
env.depends("program.o", "${inc_h}") env.depends("${build_root}/program.o", "${inc_h}")
env.Object("program.o", "program.c") env.Program("program.exe", ["program.c", "inc.c"])
env.Program("program.exe", ["program.o", "inc.c"])
env.Command("inc.c", env.Command("inc.c",
[], [],
-1
View File
@@ -4,7 +4,6 @@ build do
require 'yaml' require 'yaml'
env.add_builder(:JsonToYaml) do |params| env.add_builder(:JsonToYaml) do |params|
unless @cache.up_to_date?(@target, :JsonToYaml, @sources, @env) unless @cache.up_to_date?(@target, :JsonToYaml, @sources, @env)
print_run_message("JsonToYaml #{@target}", nil)
@cache.mkdir_p(File.dirname(@target)) @cache.mkdir_p(File.dirname(@target))
File.open(@target, 'w') do |f| File.open(@target, 'w') do |f|
f.write(YAML.dump(JSON.load(IO.read(@sources.first)))) f.write(YAML.dump(JSON.load(IO.read(@sources.first))))
@@ -1,5 +0,0 @@
build do
Environment.new do |env|
env.Program("foo.exe", glob("*.cc", "*.c"))
end
end
-6
View File
@@ -1,6 +0,0 @@
#include <stdio.h>
void foo(void)
{
printf("foo\n");
}
-12
View File
@@ -1,12 +0,0 @@
#include <iostream>
extern "C" {
void foo(void);
}
int main(int argc, char * argv[])
{
foo();
std::cout << "main" << std::endl;
return 0;
}
-4
View File
@@ -1,4 +0,0 @@
build do
sh "echo", "hi there"
sh(["echo 1 2"])
end
-4
View File
@@ -1,4 +0,0 @@
build do
sh "foobar42"
sh "echo", "continued"
end
-4
View File
@@ -1,4 +0,0 @@
build do
sh "foobar42", continue: true
sh "echo", "continued"
end
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
echo "foobar!"
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
exit 42
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
echo "flex!"
-10
View File
@@ -1,10 +0,0 @@
path_prepend "path_prepend"
path_append "path_append"
build do
Environment.new do |env|
system("flex")
system("foobar")
env.Object("simple.o", "simple.c")
end
end
-6
View File
@@ -1,6 +0,0 @@
build do
Environment.new do |env|
env.Program("simple.exe", glob("*.c"))
env.Size("simple.size", "simple.exe")
end
end
@@ -1,18 +0,0 @@
class FileBuilder < Builder
def self.name
"File"
end
def run(options)
FileUtils.mkdir_p(File.dirname(@target))
File.binwrite(@target, ENV["file_contents"])
true
end
end
build do
Environment.new do |env|
env.add_builder(FileBuilder)
env.File("^/file.txt")
program = env.Program("^/simple.exe", Dir["*.c"])
env.depends("^/simple.exe", "^/file.txt")
end
end
-10
View File
@@ -1,10 +0,0 @@
configure do
rscons "sub/Rsconscript"
rscons "sub/Rsconscript2", "configure"
puts "top configure"
end
build do
rscons "sub/Rsconscript2", "build"
puts "top build"
end
-10
View File
@@ -1,10 +0,0 @@
configure do
rscons "sub"
rscons "sub", "-f", "Rsconscript2", "configure"
puts "top configure"
end
build do
rscons "sub", "-f", "Rsconscript2", "build"
puts "top build"
end
-9
View File
@@ -1,9 +0,0 @@
configure do
rscons "sub/Rsconscript_fail"
puts "top configure"
end
build do
rscons "sub/Rsconscript2", "build"
puts "top build"
end
@@ -1,4 +0,0 @@
build do
rscons "second", "build"
puts "top build"
end
-3
View File
@@ -1,3 +0,0 @@
build do
puts "second build"
end
-7
View File
@@ -1,7 +0,0 @@
configure do
puts "sub Rsconscript configure"
end
build do
puts "sub Rsconscript build"
end
-7
View File
@@ -1,7 +0,0 @@
configure do
puts "sub Rsconscript2 configure"
end
build do
puts "sub Rsconscript2 build"
end
@@ -1,8 +0,0 @@
configure do
puts "sub Rsconscript configure"
check_program "foobarfailure"
end
build do
puts "sub Rsconscript build"
end
-6
View File
@@ -1,6 +0,0 @@
build do
Environment.new(name: "typical") do |env|
env["CPPPATH"] += glob("src/**")
env.Program("^/typical.exe", glob("src/**/*.c"))
end
end
+2 -2
View File
@@ -2,9 +2,9 @@ build do
Environment.new(echo: :command) do |env| Environment.new(echo: :command) do |env|
env.append('CPPPATH' => glob('src/**/*/')) env.append('CPPPATH' => glob('src/**/*/'))
env.add_build_hook do |builder| env.add_build_hook do |builder|
if File.basename(builder.sources.first) == "one.c" if File.basename(builder.target) == "one.o"
builder.vars["CFLAGS"] << "-O1" builder.vars["CFLAGS"] << "-O1"
elsif File.basename(builder.sources.first) == "two.c" elsif File.basename(builder.target) == "two.o"
builder.vars["CFLAGS"] << "-O2" builder.vars["CFLAGS"] << "-O2"
end end
end end
+2 -3
View File
@@ -1,10 +1,9 @@
build do build do
Environment.new(echo: :command) do |env| Environment.new(echo: :command) do |env|
env.append("CPPPATH" => glob("src/**")) env.append('CPPPATH' => glob('src/**').sort)
FileUtils.mkdir_p(env.build_root) FileUtils.mkdir_p(env.build_root)
FileUtils.mv("src/one/one.c", env.build_root) FileUtils.mv("src/one/one.c", env.build_root)
FileUtils.mv("src/two/two.c", Rscons.application.build_dir)
env.Object("^/one.o", "^/one.c") env.Object("^/one.o", "^/one.c")
env.Program("^^/program.exe", ["^/one.o", "^^/two.c"]) env.Program("program.exe", glob('src/**/*.c') + ["^/one.o"])
end end
end end
-9
View File
@@ -1,9 +0,0 @@
build do
base_env = Environment.new do |env|
env["CPPPATH"] += glob("src/**")
end
base_env.clone(name: "typical") do |env|
env.Program("^/typical.exe", glob("src/**/*.c"))
end
end
-11
View File
@@ -1,11 +0,0 @@
build do
mkdir "foo"
cd "foo" do
mkdir_p ["bar/baz", "bar/booz"]
end
mv "foo/bar", "foobar"
rmdir "foo"
touch "foobar/booz/a.txt"
cp "foobar/booz/a.txt", "foobar/baz/b.txt"
rm_rf "foobar/booz"
end
+65 -287
View File
@@ -8,7 +8,7 @@ It supports the following features:
* built-in builders for several common operations * built-in builders for several common operations
* out-of-the-box support for C, C++, and D languages * out-of-the-box support for C, C++, and D languages
* extensibility for other languages or custom builders * extensibility for other languages or custom builders
* compatible with Windows, Linux, OS X, and FreeBSD * compatible with Windows, Linux, and OS X
* colorized output with build progress * colorized output with build progress
* build hooks * build hooks
@@ -78,22 +78,10 @@ cache file in order to avoid rebuilding a target when it is already up to date.
### Build Directory ### Build Directory
Rscons was designed to store temporary build artifacts (for example, object Rscons was designed to store temporary build artifacts (for example, object
files, dependency files, etc...) and build system metadata in a files, dependency files, etc...) in a `build` directory.
"build directory".
This keeps files generated by the build cleanly separated from user-controlled This keeps files generated by the build cleanly separated from user-controlled
source files. source files.
In contrast to other build systems or build system generators, rscons executes
from the project base directory (up to the user) rather than executing from
*within* the build directory.
This keeps any file paths printed by compilers (such as in warning or error
messages) accurate relative to the project directory, so that the user does not
need to translate any paths to the correct path within a terminal or editor
application, for example.
By default a build directory named "build" is used, but this can be overridden
by the user by using the `-b`/`--build` command-line option.
## Getting Started ## Getting Started
To use Rscons on your project, you must: To use Rscons on your project, you must:
@@ -106,12 +94,11 @@ To use Rscons on your project, you must:
Rscons is designed to be distributed as a stand-alone single file script that Rscons is designed to be distributed as a stand-alone single file script that
can be copied into and versioned in a project's source tree. can be copied into and versioned in a project's source tree.
The only requirement to run Rscons is that the system has a Ruby interpreter The only dependency required to run Rscons is to have a Ruby interpreter
installed. installed.
The latest release can be downloaded from [https://github.com/holtrop/rscons/releases](https://github.com/holtrop/rscons/releases). The latest release can be downloaded from [https://github.com/holtrop/rscons/releases](https://github.com/holtrop/rscons/releases).
Simply copy the `rscons` executable script into the desired location within Simply copy the `rscons` executable script into the desired location within
the project to be built (typically the root of the repository) and mark it the project to be built (typically the root of the repository).
executable.
## Version Control Setup ## Version Control Setup
@@ -221,171 +208,6 @@ called `myprog.exe` which is to be built from all C source files found
The `Rsconscript` file is a Ruby script. The `Rsconscript` file is a Ruby script.
##> Build Script Methods
`rscons` provides several methods that a build script can use.
* `glob` (see ${#Finding Files: The glob Method})
* `path_append` (see ${#PATH Management})
* `path_components` (see ${#PATH Management})
* `path_prepend` (see ${#PATH Management})
* `path_set` (see ${#PATH Management})
* `rscons` (see ${#Using Subsidiary Build Scripts: The rscons Method})
* `sh` (see (${#Executing Commands: The sh Method})
Additionally, the following methods from the Ruby
[FileUtils](https://ruby-doc.org/stdlib-3.1.0/libdoc/fileutils/rdoc/FileUtils.html)
module are made available for the build script to call directly:
* `cd`
* `chmod`
* `chmod_R`
* `chown`
* `chown_R`
* `cp`
* `cp_lr`
* `cp_r`
* `install`
* `ln`
* `ln_s`
* `ln_sf`
* `mkdir`
* `mkdir_p`
* `mv`
* `pwd`
* `rm`
* `rm_f`
* `rm_r`
* `rm_rf`
* `rmdir`
* `touch`
###> Finding Files: The glob Method
The [`glob`](../yard/Rscons/Script/GlobalDsl.html#glob-instance_method) method can be
used to find files matching the patterns specified.
It supports a syntax similar to the Ruby [Dir.glob method](https://ruby-doc.org/core-3.1.0/Dir.html#method-c-glob) but operates more deterministically.
Example use:
```ruby
build do
Environment.new do |env|
env.Program("mytests", glob("src/**/*.cc", "test/**/*.cc"))
end
end
```
This example would build the `mytests` executable from all `.cc` source files
found recursively under the `src` or `test` directory.
###> PATH Management
`rscons` provides methods for management of the `PATH` environment variable.
The
[`path_append`](../yard/Rscons/Script/GlobalDsl.html#path_append-instance_method)
and
[`path_prepend`](../yard/Rscons/Script/GlobalDsl.html#path_prepend-instance_method)
methods can be used to append or prepend a path to the `PATH` environment
variable.
```ruby
path_prepend "i686-elf-gcc/bin"
```
The
[`path_set`](../yard/Rscons/Script/GlobalDsl.html#path_set-instance_method)
method sets the `PATH` environment variable to the given Array or String.
The
[`path_components`](../yard/Rscons/Script/GlobalDsl.html#path_components-instance_method)
method returns an Array of the components in the `PATH`
environment variable.
###> Using Subsidiary Build Scripts: The rscons Method
The
[`rscons`](../yard/Rscons/Script/GlobalDsl.html#rscons-instance_method)
build script method can be used to invoke an rscons subprocess to
perform an operation using a subsidiary rscons build script.
This can be used, for example, when a subproject is imported and a top-level
`configure` or `build` operation should also perform the same operation in the
subproject directory.
The first argument to the `rscons` method specifies either a directory name, or
the path to the subsidiary Rsconscript file to execute.
Any additional arguments are passed to `rscons` when it executes the subsidiary
script.
`rscons` will change working directories to the directory containing the
subsidiary script when executing it.
For example:
```ruby
configure do
rscons "subproject", "configure"
end
build do
rscons "subproject/Rsconscript", "build"
end
```
It is also perfectly valid to perform a different operation in the subsidiary
script from the one being performed in the top-level script.
For example, in a project that requires a particular cross compiler, the
top-level `configure` script could build the necessary cross compiler using a
subsidiary build script.
This could look something like:
```ruby
configure do
rscons "cross/Rsconscript"
check_c_compiler "i686-elf-gcc"
end
```
This would build, and if necessary first configure, using the cross/Rsconscript
subsidiary build script.
Subsidiary build scripts are executed from within the directory containing the
build script.
###> Executing Commands: The sh Method
The
[`sh`](../yard/Rscons/Script/GlobalDsl.html#sh-instance_method)
build script method can be used to directly execute commands.
The `sh` method accepts either a single String argument or an Array of Strings.
When an Array is given, if the array length is greater than 1, then the command
will not be executed and interpreted by the system shell.
Otherwise, it will be executed and interpreted by the system shell.
For example:
```ruby
build do
# Run "make" in imported "subcomponent" directory.
sh "cd subcomponent; make"
# Move a file around.
sh "mv", "subcomponent/file with spaces.txt", "new_name.txt"
end
```
If the command fails, rscons will normally print the error and terminate
execution.
If the `:continue` option is set, then rscons will not terminate execution.
For example:
```ruby
build do
# This command will fail and a message will be printed.
sh "false", continue: true
# However, due to the :continue option being set, execution will continue.
sh "echo hi"
end
```
##> Configuration Operations ##> Configuration Operations
A `configure` block is optional. A `configure` block is optional.
@@ -423,15 +245,6 @@ configure do
end end
``` ```
Global configuration options may be supplied to the compiler checks as well.
Example:
```ruby
configure do
check_c_compiler "x86_64-elf-gcc", on_fail: "Install x86_64-elf cross toolchain first!"
end
```
###> Checking for a Header File ###> Checking for a Header File
The following methods can be used to check for the presence of a header file: The following methods can be used to check for the presence of a header file:
@@ -458,6 +271,18 @@ end
Optionally specifies an array of paths to look for the header file in. Optionally specifies an array of paths to look for the header file in.
##### `:fail`
If the `:fail` option is set to `false`, then the absence of the header file
will not result in the configure option failing.
The `:fail` option defaults to `true` if the `:set_define` option is not
defined, and defaults to `false` if the `:set_define` option is defined.
##### `:set_define`
If set, a build define of the specified String will be added to the
`CPPDEFINES` construction variable array if the requested header is found.
###> Checking for a D Import ###> Checking for a D Import
The `check_d_import` method can be used to check for the presence of D import. The `check_d_import` method can be used to check for the presence of D import.
@@ -501,6 +326,18 @@ end
Optionally specifies an array of paths to look for the library in. Optionally specifies an array of paths to look for the library in.
##### `:fail`
If the `:fail` option is set to `false`, then the absence of the library
will not result in the configure option failing.
The `:fail` option defaults to `true` if the `:set_define` option is not
defined, and defaults to `false` if the `:set_define` option is defined.
##### `:set_define`
If set, a build define of the specified String will be added to the
`CPPDEFINES` construction variable array if the requested library is found.
##### `:use` ##### `:use`
If not set, the library will be used by default in all `Environment` objects. If not set, the library will be used by default in all `Environment` objects.
@@ -549,6 +386,18 @@ used to look for package configuration flags for the specified package.
If the `:program` option is given, the program specified will be used to look If the `:program` option is given, the program specified will be used to look
for configuration flags. for configuration flags.
##### `:fail`
If the `:fail` option is set to `false`, then the absence of the package or
program requested will not result in the configure option failing.
The `:fail` option defaults to `true` if the `:set_define` option is not
defined, and defaults to `false` if the `:set_define` option is defined.
##### `:set_define`
If set, a build define of the specified String will be added to the
`CPPDEFINES` construction variable array if the requested package is found.
##### `:use` ##### `:use`
If not set, the library will be used by default in all `Environment` objects. If not set, the library will be used by default in all `Environment` objects.
@@ -607,46 +456,6 @@ configure do
end end
``` ```
###> Global Configuration Check Options
#### `:fail`
If the `:fail` option is set to `false`, then the absence of the package or
program requested will not result in the configure option failing.
The `:fail` option defaults to `true` if the `:set_define` option is not
defined, and defaults to `false` if the `:set_define` option is defined.
#### `:on_fail`
The `:on_fail` option can be set to a String or a Proc object. If the
configuration operation fails (or would fail), the given message is printed
or the Proc is called.
Examples:
```ruby
configure do
check_c_compiler "special-gcc", on_fail: "First install special gcc!"
end
configure do
package_hint = lambda do
puts "The following packages must be installed to build this project:"
puts "- libsdl2-dev"
puts "- libsdl2-image-dev"
puts "- libsdl2-net-dev"
end
check_lib "SDL2", on_fail: package_hint
check_lib "SDL2_image", on_fail: package_hint
check_lib "SDL2_net", on_fail: package_hint
end
```
#### `:set_define`
If set, a build define of the specified String will be added to the
`CPPDEFINES` construction variable array if the requested package is found.
##> Build Operations ##> Build Operations
The `build` block is used to create Environments and register build targets. The `build` block is used to create Environments and register build targets.
@@ -669,26 +478,21 @@ source files found recursively under the `src` directory.
An Environment includes: An Environment includes:
- a name
- a collection of construction variables - a collection of construction variables
- a collection of build hooks - a collection of build hooks
- a collection of user-registered build targets - a collection of user-registered build targets
- a build root - a build root
All build targets must be registered within an `Environment`. All build targets must be registered within an `Environment`.
If the user does not specify a name for the environment, a name will be
automatically generated based on the Environment's internal ID, for example
"e.1".
The Environment's build root is a directory created within the top-level The Environment's build root is a directory created within the top-level
Rscons build directory. Rscons build directory.
It is based on the Environment name.
By default it holds all intermediate files generated by Rscons that are needed By default it holds all intermediate files generated by Rscons that are needed
to produce a user-specified build target. to produce a user-specified build target.
For example, for the `Rsconscript`: For example, for the `Rsconscript`:
```ruby ```ruby
build do build do
Environment.new(name: "myproj") do |env| Environment.new do |env|
env.Program("myprog.exe", glob("src/**/*.c")) env.Program("myprog.exe", glob("src/**/*.c"))
end end
end end
@@ -696,11 +500,28 @@ end
Rscons will place an object file and dependency file corresponding to each C Rscons will place an object file and dependency file corresponding to each C
source file under the Environment's build root. source file under the Environment's build root.
Assuming a top-level build directory of "build", the Environment's build root
would be "build/myproj".
This keeps the intermediate generated build artifacts separate from the source This keeps the intermediate generated build artifacts separate from the source
files. files.
###> Specifying Source Files: The glob Method
The [`glob`](../yard/Rscons/Script/Dsl.html#glob-instance_method) method can be
used to find files matching the patterns specified.
It supports a syntax similar to the Ruby [Dir.glob method](https://ruby-doc.org/core-2.5.1/Dir.html#method-c-glob) but operates more deterministically.
Example use:
```ruby
build do
Environment.new do |env|
env.Program("mytests", glob("src/**/*.cc", "test/**/*.cc"))
end
end
```
This example would build the `mytests` executable from all `.cc` source files
found recursively under the `src` or `test` directory.
###> Construction Variables ###> Construction Variables
Construction variables are values assigned to keys within an Environment. Construction variables are values assigned to keys within an Environment.
@@ -771,33 +592,20 @@ There are several default builders that are built-in to Rscons:
library. library.
* `SharedObject`, which compiles source files to produce an object file, in a * `SharedObject`, which compiles source files to produce an object file, in a
way that is able to be used to create a shared library. way that is able to be used to create a shared library.
* `Size`, which runs the 'size' utility on an executable file.
####> The Command Builder ####> The Command Builder
```ruby ```ruby
env.Command(target, sources, "CMD" => command) env.Command(target, sources, "CMD" => command)
# Example # Example
env.Command("user_guide.html", "user_guide.md", env.Command("docs.html", "docs.md",
"CMD" => ["pandoc", "-fmarkdown", "-thtml", "-o${_TARGET}", "${_SOURCES}"], "CMD" => ["pandoc", "-fmarkdown", "-thtml", "-o${_TARGET}", "${_SOURCES}"],
"CMD_DESC" => "Generating user guide:") "CMD_DESC" => "PANDOC")
``` ```
The `Command` builder executes a user-defined command in order to produce the The `Command` builder executes a user-defined command in order to produce the
desired target file based on the provided source files. desired target file based on the provided source files.
The `Command` builder supports the following construction variables:
* `CMD` (required) specifies the command to execute (an array of strings).
`CMD` is expanded for variable references, so the tokens `${_TARGET}` and
`${_SOURCES}` can be used, for example.
* `CMD_DESC` (optional) specifies the short text description to print when
the builder executes. The given description is followed by the target file
name.
* `CMD_STDOUT` (optional) specifies a file to redirect standard output to.
`CMD_STDOUT` is expanded for variable references, so the token `${_TARGET}`
can be used, for example.
####> The CFile Builder ####> The CFile Builder
```ruby ```ruby
@@ -987,36 +795,6 @@ allows it to be used to create a shared library are added.
Although it can be called explicitly, it is more commonly implicitly called by Although it can be called explicitly, it is more commonly implicitly called by
the `SharedLibrary` builder. the `SharedLibrary` builder.
####> The Size Builder
```ruby
env.Size(target, sources)
# Example
env.Program("program.exe", glob("*.c"))
env.Size("program.size", "program.exe")
```
The `Size` builder runs the "size" executable on the given source file and
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`.
###> Phony Targets
rscons supports phony build targets.
Normally, a builder produces an output file, and executes whenever the input
files or command have changed.
A phony build target can be used to register a builder that does not produce
an output file.
A custom builder can take some action when the input files change even if it
does not produce an output file.
Such a builder could perform verification or run a test on its source files,
possibly failing if some conditions are not met.
It could also simply output something to the console, such as an analysis of
the source file, whenever it changes.
A phony target is signified by passing a Symbol instead of a String as the
first parameter (target) to a builder method.
###> Explicit Dependencies ###> Explicit Dependencies
A target can be marked as depending on another file that Rscons would not A target can be marked as depending on another file that Rscons would not
@@ -1246,7 +1024,7 @@ Here is our Custom builder example extended to print its status:
```ruby ```ruby
class Rscons::Builders::Custom < Rscons::Builder class Rscons::Builders::Custom < Rscons::Builder
def run(options) def run(options)
print_run_message("Creating <target>#{@target}<reset> from Custom builder", nil) print_run_message("Creating <target>#{@target}<reset> from Custom builder")
File.open(@target, "w") do |fh| File.open(@target, "w") do |fh|
fh.write("Target file created.") fh.write("Target file created.")
end end
@@ -1271,7 +1049,7 @@ Here is a Custom builder which combines its source files similar to what the
class Rscons::Builders::Custom < Rscons::Builder class Rscons::Builders::Custom < Rscons::Builder
def run(options) def run(options)
unless @cache.up_to_date?(@target, nil, @sources, @env) unless @cache.up_to_date?(@target, nil, @sources, @env)
print_run_message("Combining <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", nil) print_run_message("Combining <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>")
File.open(@target, "wb") do |fh| File.open(@target, "wb") do |fh|
@sources.each do |source| @sources.each do |source|
fh.write(File.read(source, mode: "rb")) fh.write(File.read(source, mode: "rb"))
@@ -1498,7 +1276,7 @@ To do this, create a `configure` script with contents similar to the following:
``` ```
#!/bin/sh #!/bin/sh
exec "$(dirname "$0")"/rscons configure "$@" exec "$(dirname "$0")"/rscons "$@"
``` ```
and make it executable with `chmod +x configure`. and make it executable with `chmod +x configure`.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

+14 -6
View File
@@ -33,11 +33,10 @@ module Rscons
:Program, :Program,
:SharedLibrary, :SharedLibrary,
:SharedObject, :SharedObject,
:Size,
] ]
# Class to represent a fatal error during an Rscons operation. # Class to represent a fatal error while building a target.
class RsconsError < RuntimeError; end class BuildError < RuntimeError; end
class << self class << self
@@ -65,6 +64,16 @@ module Rscons
target.is_a?(Symbol) target.is_a?(Symbol)
end end
# Return a new path by changing the suffix in path to suffix.
#
# @param path [String] The path to alter.
# @param suffix [String] The new filename suffix, e.g. ".exe".
#
# @return [String] New path.
def set_suffix(path, suffix)
path.sub(/\.[^.]*$/, "") + suffix
end
# Return the system shell and arguments for executing a shell command. # Return the system shell and arguments for executing a shell command.
# #
# @return [Array<String>] The shell and flag. # @return [Array<String>] The shell and flag.
@@ -82,7 +91,7 @@ module Rscons
end end
if ENV["SHELL"] and ENV["SHELL"] != "" and test_shell[ENV["SHELL"], "-c"] if ENV["SHELL"] and ENV["SHELL"] != "" and test_shell[ENV["SHELL"], "-c"]
[ENV["SHELL"], "-c"] [ENV["SHELL"], "-c"]
elsif Object.const_get("RUBY_PLATFORM") =~ /mingw|msys/ elsif Object.const_get("RUBY_PLATFORM") =~ /mingw/
if test_shell["sh", "-c"] if test_shell["sh", "-c"]
# Using Rscons from MSYS should use MSYS's shell. # Using Rscons from MSYS should use MSYS's shell.
["sh", "-c"] ["sh", "-c"]
@@ -103,7 +112,7 @@ module Rscons
# @return [Array<String>] Command used to execute commands. # @return [Array<String>] Command used to execute commands.
def command_executer def command_executer
@command_executer ||= @command_executer ||=
if Object.const_get("RUBY_PLATFORM") =~ /mingw|msys/ if Object.const_get("RUBY_PLATFORM") =~ /mingw/
if ENV.keys.find {|key| key =~ /MSYS/} if ENV.keys.find {|key| key =~ /MSYS/}
begin begin
if IO.popen(["env", "echo", "success"]) {|io| io.read.strip} == "success" if IO.popen(["env", "echo", "success"]) {|io| io.read.strip} == "success"
@@ -147,7 +156,6 @@ require_relative "rscons/builders/program"
require_relative "rscons/builders/shared_library" require_relative "rscons/builders/shared_library"
require_relative "rscons/builders/shared_object" require_relative "rscons/builders/shared_object"
require_relative "rscons/builders/simple_builder" require_relative "rscons/builders/simple_builder"
require_relative "rscons/builders/size"
# language support # language support
require_relative "rscons/builders/lang/asm" require_relative "rscons/builders/lang/asm"
+1 -1
View File
@@ -84,7 +84,7 @@ module Rscons
# @return [Boolean] # @return [Boolean]
# Whether to output ANSI color escape codes. # Whether to output ANSI color escape codes.
def do_ansi?(io) def do_ansi?(io)
if RUBY_PLATFORM =~ /mingw|msys/ if RUBY_PLATFORM =~ /mingw/
(ENV["TERM"] == "xterm") && %w[fifo characterSpecial].include?(io.stat.ftype) (ENV["TERM"] == "xterm") && %w[fifo characterSpecial].include?(io.stat.ftype)
else else
io.tty? io.tty?
+7 -16
View File
@@ -5,10 +5,6 @@ module Rscons
# Functionality for an instance of the rscons application invocation. # Functionality for an instance of the rscons application invocation.
class Application class Application
# @return [String]
# Top-level build directory.
attr_accessor :build_dir
# @return [Boolean] # @return [Boolean]
# Whether to output ANSI color escape sequences. # Whether to output ANSI color escape sequences.
attr_accessor :do_ansi_color attr_accessor :do_ansi_color
@@ -27,8 +23,6 @@ module Rscons
# Create Application instance. # Create Application instance.
def initialize def initialize
@build_dir = ENV["RSCONS_BUILD_DIR"] || "build"
ENV.delete("RSCONS_BUILD_DIR")
@n_threads = Util.determine_n_threads @n_threads = Util.determine_n_threads
@vars = VarSet.new @vars = VarSet.new
@operations = Set.new @operations = Set.new
@@ -81,8 +75,6 @@ module Rscons
end end
if rv == 0 if rv == 0
build(operation_options) build(operation_options)
else
rv
end end
when "clean" when "clean"
clean clean
@@ -142,8 +134,8 @@ module Rscons
env.process env.process
end end
0 0
rescue RsconsError => e rescue BuildError => be
Ansi.write($stderr, :red, e.message, :reset, "\n") Ansi.write($stderr, :red, be.message, :reset, "\n")
1 1
end end
end end
@@ -177,8 +169,11 @@ module Rscons
# Exit code. # Exit code.
def distclean def distclean
cache = Cache.instance cache = Cache.instance
build_dir = cache["configuration_data"]["build_dir"]
clean clean
FileUtils.rm_rf(@build_dir) if build_dir
FileUtils.rm_rf(build_dir)
end
cache.clear cache.clear
0 0
end end
@@ -196,11 +191,7 @@ module Rscons
co = ConfigureOp.new(options) co = ConfigureOp.new(options)
begin begin
@script.configure(co) @script.configure(co)
rescue RsconsError => e rescue ConfigureOp::ConfigureFailure
if e.message and e.message != ""
$stderr.puts e.message
end
Ansi.write($stderr, :red, "Configuration failed", :reset, "\n")
rv = 1 rv = 1
end end
co.close(rv == 0) co.close(rv == 0)
-1
View File
@@ -57,7 +57,6 @@ module Rscons
printed_message = true printed_message = true
end end
@cache.mkdir_p(File.dirname(dest), install: @install_builder) @cache.mkdir_p(File.dirname(dest), install: @install_builder)
FileUtils.rm_f(dest)
FileUtils.cp(src, dest, :preserve => true) FileUtils.cp(src, dest, :preserve => true)
end end
@cache.register_build(dest, :Copy, [src], @env, install: @install_builder) @cache.register_build(dest, :Copy, [src], @env, install: @install_builder)
+3 -3
View File
@@ -75,10 +75,10 @@ module Rscons
@vars["_SOURCES"] = @sources @vars["_SOURCES"] = @sources
depfilesuffix = @env.expand_varref("${DEPFILESUFFIX}", vars) depfilesuffix = @env.expand_varref("${DEPFILESUFFIX}", vars)
@vars["_DEPFILE"] = @vars["_DEPFILE"] =
if @vars[:direct] || !@target.start_with?("#{@env.build_root}/") if @vars[:direct]
@env.get_build_fname(@target, depfilesuffix, self.class) @env.get_build_fname(target, depfilesuffix, self.class)
else else
"#{@target}#{depfilesuffix}" Rscons.set_suffix(target, depfilesuffix)
end end
@cache.mkdir_p(File.dirname(@vars["_DEPFILE"])) @cache.mkdir_p(File.dirname(@vars["_DEPFILE"]))
command = @env.build_command(@command_template, @vars) command = @env.build_command(@command_template, @vars)
+1 -1
View File
@@ -23,7 +23,7 @@ module Rscons
@vars["_PREPROCESS_DEPGEN"] = depgen @vars["_PREPROCESS_DEPGEN"] = depgen
@vars["_TARGET"] = @target @vars["_TARGET"] = @target
@vars["_SOURCES"] = @sources @vars["_SOURCES"] = @sources
@vars["_DEPFILE"] = "#{target}#{env.expand_varref("${DEPFILESUFFIX}", vars)}" @vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
command = @env.build_command("${CPP_CMD}", @vars) command = @env.build_command("${CPP_CMD}", @vars)
self.produces(@vars["_DEPFILE"]) self.produces(@vars["_DEPFILE"])
standard_command("Preprocessing <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command) standard_command("Preprocessing <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
-24
View File
@@ -1,24 +0,0 @@
module Rscons
module Builders
# Run the "size" utility on an executable and store its results in the
# target file.
# input file.
#
# Examples::
# env.Size("^/project.size", "^/project.elf")
class Size < Builder
# Run the builder to produce a build target.
def run(options)
if @command
finalize_command
else
@vars["_SOURCES"] = @sources
command = @env.build_command("${SIZECMD}", @vars)
standard_command("Size <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command, stdout: @target)
end
end
end
end
end
+7 -9
View File
@@ -51,6 +51,9 @@ module Rscons
# } # }
class Cache class Cache
# Name of the file to store cache information in
CACHE_FILE = ".rsconscache"
# Prefix for phony cache entries. # Prefix for phony cache entries.
PHONY_PREFIX = ":PHONY:" PHONY_PREFIX = ":PHONY:"
@@ -67,11 +70,6 @@ module Rscons
initialize! initialize!
end end
# Get the path to the cache file.
def cache_file
File.join(Rscons.application.build_dir, ".rsconscache")
end
# Access cache value. # Access cache value.
def [](key) def [](key)
@cache[key] @cache[key]
@@ -86,7 +84,7 @@ module Rscons
# #
# @return [void] # @return [void]
def clear def clear
FileUtils.rm_f(cache_file) FileUtils.rm_f(CACHE_FILE)
initialize! initialize!
end end
@@ -102,7 +100,7 @@ module Rscons
# @return [void] # @return [void]
def write def write
@cache["version"] = VERSION @cache["version"] = VERSION
File.open(cache_file, "w") do |fh| File.open(CACHE_FILE, "w") do |fh|
fh.puts(JSON.dump(@cache)) fh.puts(JSON.dump(@cache))
end end
end end
@@ -362,9 +360,9 @@ module Rscons
# Create a Cache object and load in the previous contents from the cache # Create a Cache object and load in the previous contents from the cache
# file. # file.
def initialize! def initialize!
@cache = JSON.load(File.read(cache_file)) rescue {} @cache = JSON.load(File.read(CACHE_FILE)) rescue {}
unless @cache.is_a?(Hash) unless @cache.is_a?(Hash)
$stderr.puts "Warning: #{cache_file} was corrupt. Contents:\n#{@cache.inspect}" $stderr.puts "Warning: #{CACHE_FILE} was corrupt. Contents:\n#{@cache.inspect}"
@cache = {} @cache = {}
end end
@cache["targets"] ||= {} @cache["targets"] ||= {}
+10 -8
View File
@@ -6,14 +6,11 @@ USAGE = <<EOF
Usage: #{$0} [global options] [operation] [operation options] Usage: #{$0} [global options] [operation] [operation options]
Global options: Global options:
-b BUILD, --build=BUILD Set build directory (default: build)
-f FILE Use FILE as Rsconscript
-F, --show-failure Show failed command log from previous build and exit -F, --show-failure Show failed command log from previous build and exit
--version Show rscons version and exit
-h, --help Show rscons help and exit -h, --help Show rscons help and exit
-j N, --nthreads=N Set number of threads (local default: #{Rscons.application.n_threads})
-r COLOR, --color=COLOR Set color mode (off, auto, force) -r COLOR, --color=COLOR Set color mode (off, auto, force)
-v, --verbose Run verbosely -v, --verbose Run verbosely
--version Show rscons version and exit
Operations: Operations:
configure Configure the project configure Configure the project
@@ -24,7 +21,12 @@ Operations:
uninstall Uninstall project from installation destination uninstall Uninstall project from installation destination
Configure options: Configure options:
-b BUILD, --build=BUILD Set build directory (default: build)
--prefix=PREFIX Set installation prefix (default: /usr/local) --prefix=PREFIX Set installation prefix (default: /usr/local)
Build options:
-j N, --nthreads=N Set number of threads (local default: #{Rscons.application.n_threads})
EOF EOF
module Rscons module Rscons
@@ -56,10 +58,6 @@ module Rscons
private private
def add_global_options(opts) def add_global_options(opts)
opts.on("-b", "--build DIR") do |build_dir|
Rscons.application.build_dir = build_dir
end
opts.on("-j NTHREADS") do |n_threads| opts.on("-j NTHREADS") do |n_threads|
Rscons.application.n_threads = n_threads.to_i Rscons.application.n_threads = n_threads.to_i
end end
@@ -160,6 +158,10 @@ module Rscons
end end
def parse_configure_args(opts, argv, options) def parse_configure_args(opts, argv, options)
opts.on("-b", "--build DIR") do |build_dir|
options[:build_dir] = build_dir
end
opts.on("--prefix PREFIX") do |prefix| opts.on("--prefix PREFIX") do |prefix|
options[:prefix] = prefix options[:prefix] = prefix
end end
+49 -49
View File
@@ -5,29 +5,37 @@ module Rscons
# Class to manage a configure operation. # Class to manage a configure operation.
class ConfigureOp class ConfigureOp
# Exception raised when a configuration error occurs.
class ConfigureFailure < Exception; end
# Create a ConfigureOp. # Create a ConfigureOp.
# #
# @param options [Hash] # @param options [Hash]
# Optional parameters. # Optional parameters.
# @option options [String] :build_dir
# Build directory.
# @option options [String] :prefix # @option options [String] :prefix
# Install prefix. # Install prefix.
# @option options [String] :project_name # @option options [String] :project_name
# Project name. # Project name.
def initialize(options) def initialize(options)
# Default options. # Default options.
options[:build_dir] ||= "build"
options[:prefix] ||= "/usr/local" options[:prefix] ||= "/usr/local"
@work_dir = "#{Rscons.application.build_dir}/_configure" @work_dir = "#{options[:build_dir]}/configure"
FileUtils.mkdir_p(@work_dir) FileUtils.mkdir_p(@work_dir)
@log_fh = File.open("#{@work_dir}/config.log", "wb") @log_fh = File.open("#{@work_dir}/config.log", "wb")
cache = Cache.instance cache = Cache.instance
cache["failed_commands"] = [] cache["failed_commands"] = []
cache["configuration_data"] = {} cache["configuration_data"] = {}
cache["configuration_data"]["build_dir"] = options[:build_dir]
cache["configuration_data"]["prefix"] = options[:prefix] cache["configuration_data"]["prefix"] = options[:prefix]
if project_name = options[:project_name] if project_name = options[:project_name]
Ansi.write($stdout, "Configuring ", :cyan, project_name, :reset, "...\n") Ansi.write($stdout, "Configuring ", :cyan, project_name, :reset, "...\n")
else else
$stdout.puts "Configuring project..." $stdout.puts "Configuring project..."
end end
Ansi.write($stdout, "Setting build directory... ", :green, options[:build_dir], :reset, "\n")
Ansi.write($stdout, "Setting prefix... ", :green, options[:prefix], :reset, "\n") Ansi.write($stdout, "Setting prefix... ", :green, options[:prefix], :reset, "\n")
store_merge("prefix" => options[:prefix]) store_merge("prefix" => options[:prefix])
end end
@@ -54,10 +62,6 @@ module Rscons
# @return [void] # @return [void]
def check_c_compiler(*ccc) def check_c_compiler(*ccc)
$stdout.write("Checking for C compiler... ") $stdout.write("Checking for C compiler... ")
options = {}
if ccc.last.is_a?(Hash)
options = ccc.slice!(-1)
end
if ccc.empty? if ccc.empty?
# Default C compiler search array. # Default C compiler search array.
ccc = %w[gcc clang] ccc = %w[gcc clang]
@@ -65,7 +69,7 @@ module Rscons
cc = ccc.find do |cc| cc = ccc.find do |cc|
test_c_compiler(cc) test_c_compiler(cc)
end end
complete(cc ? 0 : 1, options.merge(success_message: cc)) complete(cc ? 0 : 1, success_message: cc)
end end
# Check for a working C++ compiler. # Check for a working C++ compiler.
@@ -76,10 +80,6 @@ module Rscons
# @return [void] # @return [void]
def check_cxx_compiler(*ccc) def check_cxx_compiler(*ccc)
$stdout.write("Checking for C++ compiler... ") $stdout.write("Checking for C++ compiler... ")
options = {}
if ccc.last.is_a?(Hash)
options = ccc.slice!(-1)
end
if ccc.empty? if ccc.empty?
# Default C++ compiler search array. # Default C++ compiler search array.
ccc = %w[g++ clang++] ccc = %w[g++ clang++]
@@ -87,7 +87,7 @@ module Rscons
cc = ccc.find do |cc| cc = ccc.find do |cc|
test_cxx_compiler(cc) test_cxx_compiler(cc)
end end
complete(cc ? 0 : 1, options.merge(success_message: cc)) complete(cc ? 0 : 1, success_message: cc)
end end
# Check for a working D compiler. # Check for a working D compiler.
@@ -98,10 +98,6 @@ module Rscons
# @return [void] # @return [void]
def check_d_compiler(*cdc) def check_d_compiler(*cdc)
$stdout.write("Checking for D compiler... ") $stdout.write("Checking for D compiler... ")
options = {}
if cdc.last.is_a?(Hash)
options = cdc.slice!(-1)
end
if cdc.empty? if cdc.empty?
# Default D compiler search array. # Default D compiler search array.
cdc = %w[gdc ldc2] cdc = %w[gdc ldc2]
@@ -109,7 +105,7 @@ module Rscons
dc = cdc.find do |dc| dc = cdc.find do |dc|
test_d_compiler(dc) test_d_compiler(dc)
end end
complete(dc ? 0 : 1, options.merge(success_message: dc)) complete(dc ? 0 : 1, success_message: dc)
end end
# Check for a package or configure program output. # Check for a package or configure program output.
@@ -284,19 +280,12 @@ module Rscons
# Execute a test command and log the result. # Execute a test command and log the result.
# #
# @param command [Array<String>]
# Command to execute.
# @param options [Hash]
# Optional arguments.
# @option options [String] :stdin
# Data to send to standard input stream of the executed command.
#
# @return [String, String, Process::Status] # @return [String, String, Process::Status]
# stdout, stderr, status # stdout, stderr, status
def log_and_test_command(command, options = {}) def log_and_test_command(command)
begin begin
@log_fh.puts("Command: #{command.join(" ")}") @log_fh.puts("Command: #{command.join(" ")}")
stdout, stderr, status = Open3.capture3(*command, stdin_data: options[:stdin]) stdout, stderr, status = Open3.capture3(*command)
@log_fh.puts("Exit status: #{status.to_i}") @log_fh.puts("Exit status: #{status.to_i}")
@log_fh.write(stdout) @log_fh.write(stdout)
@log_fh.write(stderr) @log_fh.write(stderr)
@@ -391,15 +380,11 @@ module Rscons
else else
!options[:set_define] !options[:set_define]
end end
color = should_fail ? :red : :yellow
Ansi.write($stdout, color, "#{fail_message}\n")
if options[:on_fail].is_a?(String)
$stdout.puts(options[:on_fail])
elsif options[:on_fail].is_a?(Proc)
options[:on_fail].call
end
if should_fail if should_fail
raise RsconsError.new Ansi.write($stdout, :red, "#{fail_message}\n")
raise ConfigureFailure.new
else
Ansi.write($stdout, :yellow, "#{fail_message}\n")
end end
end end
end end
@@ -416,19 +401,24 @@ module Rscons
def test_c_compiler(cc) def test_c_compiler(cc)
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh| File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
fh.puts <<-EOF fh.puts <<-EOF
int fun(int val) { #include <stdio.h>
return val * 2; int main(int argc, char * argv[]) {
printf("Success.\\n");
return 0;
} }
EOF EOF
end end
command = %W[#{cc} -c -o #{@work_dir}/cfgtest.o #{@work_dir}/cfgtest.c] command = %W[#{cc} -o #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.c]
merge = {"CC" => cc} merge = {"CC" => cc}
_, _, status = log_and_test_command(command) _, _, status = log_and_test_command(command)
if status == 0 if status == 0
stdout, _, status = log_and_test_command(["#{@work_dir}/cfgtest.exe"])
if status == 0 and stdout =~ /Success/
store_merge(merge) store_merge(merge)
true true
end end
end end
end
# Test a C++ compiler. # Test a C++ compiler.
# #
@@ -440,20 +430,25 @@ module Rscons
def test_cxx_compiler(cc) def test_cxx_compiler(cc)
File.open("#{@work_dir}/cfgtest.cxx", "wb") do |fh| File.open("#{@work_dir}/cfgtest.cxx", "wb") do |fh|
fh.puts <<-EOF fh.puts <<-EOF
template<typename T> #include <iostream>
T fun(T val) { using namespace std;
return val * 2; int main(int argc, char * argv[]) {
cout << "Success." << endl;
return 0;
} }
EOF EOF
end end
command = %W[#{cc} -c -o #{@work_dir}/cfgtest.o #{@work_dir}/cfgtest.cxx] command = %W[#{cc} -o #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.cxx]
merge = {"CXX" => cc} merge = {"CXX" => cc}
_, _, status = log_and_test_command(command) _, _, status = log_and_test_command(command)
if status == 0 if status == 0
stdout, _, status = log_and_test_command(["#{@work_dir}/cfgtest.exe"])
if status == 0 and stdout =~ /Success/
store_merge(merge) store_merge(merge)
true true
end end
end end
end
# Test a D compiler. # Test a D compiler.
# #
@@ -465,8 +460,9 @@ module Rscons
def test_d_compiler(dc) def test_d_compiler(dc)
File.open("#{@work_dir}/cfgtest.d", "wb") do |fh| File.open("#{@work_dir}/cfgtest.d", "wb") do |fh|
fh.puts <<-EOF fh.puts <<-EOF
import core.math; import std.stdio;
int fun() { int main() {
writeln("Success.");
return 0; return 0;
} }
EOF EOF
@@ -474,28 +470,32 @@ module Rscons
[:gdc, :ldc2].find do |dc_test| [:gdc, :ldc2].find do |dc_test|
case dc_test case dc_test
when :gdc when :gdc
command = %W[#{dc} -c -o #{@work_dir}/cfgtest.o #{@work_dir}/cfgtest.d] command = %W[#{dc} -o #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.d]
merge = {"DC" => dc} merge = {"DC" => dc}
when :ldc2 when :ldc2
# ldc2 on Windows expect an object file suffix of .obj. command = %W[#{dc} -of #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.d]
ldc_objsuffix = RUBY_PLATFORM =~ /mingw|msys/ ? ".obj" : ".o"
command = %W[#{dc} -c -of #{@work_dir}/cfgtest#{ldc_objsuffix} #{@work_dir}/cfgtest.d]
env = BasicEnvironment.new env = BasicEnvironment.new
merge = { merge = {
"DC" => dc, "DC" => dc,
"DCCMD" => env["DCCMD"].map {|e| e.sub(/^-o$/, "-of")}, "DCCMD" => env["DCCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
"LDCMD" => env["LDCMD"].map {|e| e.sub(/^-o$/, "-of")}, "LDCMD" => env["LDCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
"DDEPGEN" => ["-deps=${_DEPFILE}"], "DDEPGEN" => ["-deps=${_DEPFILE}"],
} }
merge["OBJSUFFIX"] = [ldc_objsuffix] if RUBY_PLATFORM =~ /mingw/
# ldc2 on Windows expect an object file suffix of .obj.
merge["OBJSUFFIX"] = %w[.obj]
end
end end
_, _, status = log_and_test_command(command) _, _, status = log_and_test_command(command)
if status == 0 if status == 0
stdout, _, status = log_and_test_command(["#{@work_dir}/cfgtest.exe"])
if status == 0 and stdout =~ /Success/
store_merge(merge) store_merge(merge)
true true
end end
end end
end end
end
# Common functionality for all store methods. # Common functionality for all store methods.
# #
+1 -4
View File
@@ -1,6 +1,6 @@
module Rscons module Rscons
on_windows = RUBY_PLATFORM =~ /mingw|msys|cygwin/ on_windows = RUBY_PLATFORM =~ /mingw|cygwin/
pic_flags = on_windows ? [] : %w[-fPIC] pic_flags = on_windows ? [] : %w[-fPIC]
# Default Rscons construction variables. # Default Rscons construction variables.
@@ -80,9 +80,6 @@ module Rscons
"SHLIBLINKPREFIX" => "-l", "SHLIBLINKPREFIX" => "-l",
"SHLIBPREFIX" => on_windows ? "" : "lib", "SHLIBPREFIX" => on_windows ? "" : "lib",
"SHLIBSUFFIX" => on_windows ? ".dll" : ".so", "SHLIBSUFFIX" => on_windows ? ".dll" : ".so",
"SIZE" => "size",
"SIZECMD" => %w[${SIZE} ${SIZEFLAGS} ${_SOURCES}],
"SIZEFLAGS" => [],
"YACC" => "bison", "YACC" => "bison",
"YACCSUFFIX" => %w[.y .yy], "YACCSUFFIX" => %w[.y .yy],
"YACC_CMD" => %w[${YACC} ${YACC_FLAGS} -o ${_TARGET} ${_SOURCES}], "YACC_CMD" => %w[${YACC} ${YACC_FLAGS} -o ${_TARGET} ${_SOURCES}],
+17 -23
View File
@@ -1,6 +1,7 @@
require "fileutils" require "fileutils"
require "set" require "set"
require "shellwords" require "shellwords"
require "thwait"
module Rscons module Rscons
# The Environment class is the main programmatic interface to Rscons. It # The Environment class is the main programmatic interface to Rscons. It
@@ -51,10 +52,6 @@ module Rscons
# global Rscons.application.n_threads value. # global Rscons.application.n_threads value.
attr_accessor :n_threads attr_accessor :n_threads
# @return [String]
# Environment name.
attr_reader :name
# Create an Environment object. # Create an Environment object.
# #
# @param options [Hash] # @param options [Hash]
@@ -62,9 +59,6 @@ module Rscons
# :command, :short, or :off (default :short) # :command, :short, or :off (default :short)
# @option options [Boolean] :exclude_builders # @option options [Boolean] :exclude_builders
# Whether to omit adding default builders (default false) # Whether to omit adding default builders (default false)
# @option options [String, nil] :name
# Environment name. This determines the folder name used to store all
# environment build files under the top-level build directory.
# @option options [String, Array<String>] :use # @option options [String, Array<String>] :use
# Use flag(s). If specified, any configuration flags which were saved # Use flag(s). If specified, any configuration flags which were saved
# with a corresponding `:use` value will be applied to this Environment. # with a corresponding `:use` value will be applied to this Environment.
@@ -104,8 +98,7 @@ module Rscons
else else
:short :short
end end
@name = options[:name] || "e.#{@id}" @build_root = "#{Cache.instance["configuration_data"]["build_dir"]}/e.#{@id}"
@build_root = "#{Rscons.application.build_dir}/#{@name}"
@n_threads = Rscons.application.n_threads @n_threads = Rscons.application.n_threads
if block_given? if block_given?
@@ -133,14 +126,14 @@ module Rscons
# #
# @return [Environment] The newly created {Environment} object. # @return [Environment] The newly created {Environment} object.
def clone(options = {}) def clone(options = {})
options = options.dup
clone = options[:clone] || :all clone = options[:clone] || :all
clone = Set[:variables, :builders, :build_hooks] if clone == :all clone = Set[:variables, :builders, :build_hooks] if clone == :all
clone = Set[] if clone == :none clone = Set[] if clone == :none
clone = Set.new(clone) if clone.is_a?(Array) clone = Set.new(clone) if clone.is_a?(Array)
clone.delete(:builders) if options[:exclude_builders] clone.delete(:builders) if options[:exclude_builders]
options[:echo] ||= @echo env = self.class.new(
env = self.class.new(options.merge(exclude_builders: true)) echo: options[:echo] || @echo,
exclude_builders: true)
if clone.include?(:builders) if clone.include?(:builders)
@builders.each do |builder_name, builder| @builders.each do |builder_name, builder|
env.add_builder(builder) env.add_builder(builder)
@@ -258,7 +251,7 @@ module Rscons
if extra_path = builder_class.extra_path if extra_path = builder_class.extra_path
extra_path = "/#{extra_path}" extra_path = "/#{extra_path}"
end end
"#{@build_root}#{extra_path}/#{Util.make_relative_path("#{source_fname}#{suffix}")}".gsub("\\", "/") "#{@build_root}#{extra_path}/#{Util.make_relative_path(Rscons.set_suffix(source_fname, suffix))}".gsub("\\", "/")
end end
# Build all build targets specified in the Environment. # Build all build targets specified in the Environment.
@@ -294,9 +287,9 @@ module Rscons
unless @process_failures.empty? unless @process_failures.empty?
msg = @process_failures.join("\n") msg = @process_failures.join("\n")
if Cache.instance["failed_commands"].size > 0 if Cache.instance["failed_commands"].size > 0
msg += "\nUse `#{Util.command_to_execute_me} -F` to view the failed command log from the previous build operation" msg += "\nUse -F to view the failed command log from the previous build operation"
end end
raise RsconsError.new(msg) raise BuildError.new(msg)
end end
end end
@@ -354,12 +347,12 @@ module Rscons
if target.is_a?(Builder) if target.is_a?(Builder)
target = target.target target = target.target
end end
target = expand_path(expand_varref(target.to_s)) target = expand_varref(target.to_s)
user_deps = user_deps.map do |ud| user_deps = user_deps.map do |ud|
if ud.is_a?(Builder) if ud.is_a?(Builder)
ud = ud.target ud = ud.target
end end
expand_path(expand_varref(ud)) expand_varref(ud)
end end
@user_deps[target] ||= [] @user_deps[target] ||= []
@user_deps[target] = (@user_deps[target] + user_deps).uniq @user_deps[target] = (@user_deps[target] + user_deps).uniq
@@ -475,12 +468,10 @@ module Rscons
output_fname output_fname
end end
# Expand paths. # Expand a path to be relative to the Environment's build root.
# #
# Paths beginning with "^/" are expanded by replacing "^" with the # Paths beginning with "^/" are expanded by replacing "^" with the
# Environment's build root (e.g. "build/envname"). # Environment's build root.
# Paths beginning with "^^/" are expanded by replacing "^^" with the
# top-level build directory (e.g. "build").
# #
# @param path [String, Array<String>] # @param path [String, Array<String>]
# The path(s) to expand. # The path(s) to expand.
@@ -495,7 +486,7 @@ module Rscons
expand_path(path) expand_path(path)
end end
else else
path.sub(%r{^\^\^(?=[\\/])}, Rscons.application.build_dir).sub(%r{^\^(?=[\\/])}, @build_root).gsub("\\", "/") path.sub(%r{^\^(?=[\\/])}, @build_root).gsub("\\", "/")
end end
end end
@@ -711,7 +702,10 @@ module Rscons
!thread.alive? !thread.alive?
end end
else else
Util.wait_for_thread(*@threads.keys) if @threads.empty?
raise "No threads to wait for"
end
ThreadsWait.new(*@threads.keys).next_wait
end end
end end
+27 -187
View File
@@ -3,8 +3,32 @@ module Rscons
# The Script class encapsulates the state of a build script. # The Script class encapsulates the state of a build script.
class Script class Script
# Global DSL methods. # DSL available to the Rsconscript.
class GlobalDsl class Dsl
# Create a Dsl.
def initialize(script)
@script = script
end
# Set the project name.
def project_name(project_name)
@script.project_name = project_name
end
# Whether to automatically configure (default true).
def autoconf(autoconf)
@script.autoconf = autoconf
end
# Enter build block.
def build(&block)
@script.operations["build"] = block
end
# Enter configuration block.
def configure(&block)
@script.operations["configure"] = block
end
# Return a list of paths matching the specified pattern(s). # Return a list of paths matching the specified pattern(s).
# #
@@ -32,194 +56,10 @@ module Rscons
end end
end.sort end.sort
end end
# Return path components from the PATH variable.
#
# @return [Array<String>]
# Path components from the PATH variable.
def path_components
ENV["PATH"].split(File::PATH_SEPARATOR)
end
# Prepend a path component to the PATH variable.
#
# @param path [String]
# Path to prepend.
#
# @return [void]
def path_prepend(path)
path_set([File.expand_path(path)] + path_components)
end
# Append a path component to the PATH variable.
#
# @param path [String]
# Path to append.
#
# @return [void]
def path_append(path)
path_set(path_components + [File.expand_path(path)])
end
# Set the PATH variable.
#
# @param new_path [String, Array<String>]
# New PATH variable value as an array or string.
#
# @return [void]
def path_set(new_path)
if new_path.is_a?(Array)
new_path = new_path.join(File::PATH_SEPARATOR)
end
ENV["PATH"] = new_path
end
# Invoke rscons in a subprocess for a subsidiary Rsconscript file.
#
# @param path [String]
# Path to subsidiary Rsconscript to execute, or path to subsidiary
# directory to run rscons in.
# @param args[Array<String>]
# Arguments to pass to rscons subprocess.
def rscons(path, *args)
rscons_path = File.expand_path($0)
path = File.expand_path(path)
if File.directory?(path)
command = [*args]
dir = path
else
command = ["-f", path, *args]
dir = File.dirname(path)
end
if File.exist?("#{dir}/rscons")
rscons_path = "#{dir}/rscons"
end
command = [rscons_path] + command
print_dir = dir != "." && dir != File.expand_path(Dir.pwd)
if ENV["specs"] and not ENV["dist_specs"] # specs
command = ["ruby", $LOAD_PATH.map {|p| ["-I", p]}, command].flatten # specs
end # specs
puts "rscons: Entering directory '#{dir}'" if print_dir
result = system(*command, chdir: dir)
puts "rscons: Leaving directory '#{dir}'" if print_dir
unless result
raise RsconsError.new("Failed command: " + command.join(" "))
end
end
# Execute a shell command, exiting on failure.
# The behavior to exit on failure is suppressed if the +:continue+
# option is given.
#
# @overload sh(command, options = {})
# @param command [String, Array<String>]
# Command to execute. The command is executed and interpreted by the
# system shell when given as a single string. It is not passed to the
# system shell if the array size is greater than 1.
# @param options [Hash]
# Options.
# @option options [Boolean] :continue
# If set to +true+, rscons will continue executing afterward, even if
# the command fails.
#
# @overload sh(*command, options = {})
# @param command [String, Array<String>]
# Command to execute. The command is executed and interpreted by the
# system shell when given as a single string. It is not passed to the
# system shell if the array size is greater than 1.
# @param options [Hash]
# Options.
# @option options [Boolean] :continue
# If set to +true+, rscons will continue executing afterward, even if
# the command fails.
def sh(*command)
options = {}
if command.last.is_a?(Hash)
options = command.slice!(-1)
end
if command.size == 1 && command[0].is_a?(Array)
command = command[0]
end
if Rscons.application.verbose
if command.size > 1
puts Util.command_to_s(command)
else
puts command[0]
end
end
begin
system(*command, exception: true)
rescue StandardError => e
message = "#{e.backtrace[2]}: #{e.message}"
if options[:continue]
Ansi.write($stderr, :red, message, :reset, "\n")
else
raise RsconsError.new(message)
end
end
end
[
:cd,
:chmod,
:chmod_R,
:chown,
:chown_R,
:cp,
:cp_lr,
:cp_r,
:install,
:ln,
:ln_s,
:ln_sf,
:mkdir,
:mkdir_p,
:mv,
:pwd,
:rm,
:rm_f,
:rm_r,
:rm_rf,
:rmdir,
:touch,
].each do |method|
define_method(method) do |*args, **kwargs, &block|
FileUtils.__send__(method, *args, **kwargs, &block)
end
end
end
# Top-level DSL available to the Rsconscript.
class Dsl < GlobalDsl
# Create a Dsl.
def initialize(script)
@script = script
end
# Set the project name.
def project_name(project_name)
@script.project_name = project_name
end
# Whether to automatically configure (default true).
def autoconf(autoconf)
@script.autoconf = autoconf
end
# Enter build block.
def build(&block)
@script.operations["build"] = block
end
# Enter configuration block.
def configure(&block)
@script.operations["configure"] = block
end
end end
# DSL available to the 'configure' block. # DSL available to the 'configure' block.
class ConfigureDsl < GlobalDsl class ConfigureDsl
# Create a ConfigureDsl. # Create a ConfigureDsl.
# #
# @param configure_op [ConfigureOp] # @param configure_op [ConfigureOp]
+5 -42
View File
@@ -9,7 +9,7 @@ module Rscons
# #
# @return [Boolean] Whether the given path is an absolute filesystem path. # @return [Boolean] Whether the given path is an absolute filesystem path.
def absolute_path?(path) def absolute_path?(path)
if RUBY_PLATFORM =~ /mingw|msys/ if RUBY_PLATFORM =~ /mingw/
path =~ %r{^(?:\w:)?[\\/]} path =~ %r{^(?:\w:)?[\\/]}
else else
path.start_with?("/") path.start_with?("/")
@@ -48,7 +48,7 @@ module Rscons
# @return [String] # @return [String]
# The string representation of the command. # The string representation of the command.
def command_to_s(command) def command_to_s(command)
command.map { |c| c[" "] ? "'#{c.gsub("'", "'\\\\''")}'" : c }.join(" ") command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ')
end end
# Determine the number of threads to use by default. # Determine the number of threads to use by default.
@@ -68,8 +68,8 @@ module Rscons
case RbConfig::CONFIG["host_os"] case RbConfig::CONFIG["host_os"]
when /linux/ when /linux/
return File.read("/proc/cpuinfo").scan(/^processor\s*:/).size return File.read("/proc/cpuinfo").scan(/^processor\s*:/).size
when /mswin|mingw|msys/ when /mswin|mingw/
if `wmic cpu get NumberOfLogicalProcessors -value` =~ /NumberOfLogicalProcessors=(\d+)/ if `wmic cpu get NumberOfLogicalProcessors /value` =~ /NumberOfLogicalProcessors=(\d+)/
return $1.to_i return $1.to_i
end end
when /darwin/ when /darwin/
@@ -191,40 +191,6 @@ module Rscons
deps deps
end end
# Wait for any of a number of threads to complete.
#
# @param threads [Array<Thread>]
# Threads to wait for.
#
# @return [Thread]
# The Thread that completed.
def wait_for_thread(*threads)
if threads.empty?
raise "No threads to wait for"
end
queue = Queue.new
threads.each do |thread|
# Create a wait thread for each thread we're waiting for.
Thread.new do
begin
thread.join
ensure
queue.push(thread)
end
end
end
# Wait for any thread to complete.
queue.pop
end
# Command that can be run to execute this instance of rscons from the
# current working directory.
def command_to_execute_me
command = Pathname.new(File.expand_path($0)).relative_path_from(Dir.pwd).to_s
command = "./#{command}" unless command["/"]
command
end
private private
# Check if a directory contains a certain executable. # Check if a directory contains a certain executable.
@@ -233,14 +199,11 @@ module Rscons
# Directory to look in. # Directory to look in.
# @param executable [String] # @param executable [String]
# Executable to look for. # Executable to look for.
#
# @return [String, nil]
# Executable found.
def test_path_for_executable(path_entry, executable) def test_path_for_executable(path_entry, executable)
is_executable = lambda do |path| is_executable = lambda do |path|
File.file?(path) and File.executable?(path) File.file?(path) and File.executable?(path)
end end
if RbConfig::CONFIG["host_os"] =~ /mswin|windows|mingw|msys/i if RbConfig::CONFIG["host_os"] =~ /mswin|windows|mingw/i
if File.directory?(path_entry) if File.directory?(path_entry)
executable = executable.downcase executable = executable.downcase
dir_entries = Dir.entries(path_entry) dir_entries = Dir.entries(path_entry)
+1 -1
View File
@@ -1,4 +1,4 @@
module Rscons module Rscons
# Project version. # Project version.
VERSION = "2.3.0" VERSION = "2.0.0beta2"
end end
+1 -6
View File
@@ -1,6 +1,6 @@
<html> <html>
<head> <head>
<title>Rscons User Guide<%= subpage_title %> - Version <%= Rscons::VERSION %></title> <title>RScons User Guide<%= subpage_title %> - Version <%= Rscons::VERSION %></title>
<style> <style>
body { body {
background-color: #CCC; background-color: #CCC;
@@ -31,11 +31,6 @@
.separator { .separator {
height: 2em; height: 2em;
} }
.img_block_center {
display: block;
margin-left: auto;
margin-right: auto;
}
.page_nav { .page_nav {
width: 100%; width: 100%;
table-layout: fixed; table-layout: fixed;
+4 -7
View File
@@ -44,7 +44,7 @@ combine_files[START_FILE]
# Strip Ruby comment lines and empty lines to save some space, but do not # Strip Ruby comment lines and empty lines to save some space, but do not
# remove lines that are in heredoc sections. This isn't terribly robust to be # remove lines that are in heredoc sections. This isn't terribly robust to be
# used in the wild, but works for the heredoc instances for this project. # used in the wild, but works for the heredoc instances for this project.
stripped = [] stripped_comments = []
heredoc_end = nil heredoc_end = nil
combined_file.each do |line| combined_file.each do |line|
if line =~ /<<-?([A-Z]+)/ if line =~ /<<-?([A-Z]+)/
@@ -53,20 +53,17 @@ combined_file.each do |line|
if heredoc_end and line =~ /^\s*#{heredoc_end}/ if heredoc_end and line =~ /^\s*#{heredoc_end}/
heredoc_end = nil heredoc_end = nil
end end
if line !~ /#\sspecs/ if heredoc_end or not (line =~ /^\s*(#[^!].*)?$/)
if heredoc_end or line !~ /^\s*(#[^!].*)?$/ stripped_comments << line
stripped << line
end
end end
end end
require "zlib" require "zlib"
require "base64" require "base64"
compressed_script = Zlib::Deflate.deflate(stripped.join) compressed_script = Zlib::Deflate.deflate(stripped_comments.join)
encoded_compressed_script = Base64.encode64(compressed_script).gsub("\n", "") encoded_compressed_script = Base64.encode64(compressed_script).gsub("\n", "")
hash = Digest::MD5.hexdigest(encoded_compressed_script) hash = Digest::MD5.hexdigest(encoded_compressed_script)
FileUtils.rm_rf(DIST)
FileUtils.mkdir_p(DIST) FileUtils.mkdir_p(DIST)
File.open("#{DIST}/#{PROG_NAME}", "wb", 0755) do |fh| File.open("#{DIST}/#{PROG_NAME}", "wb", 0755) do |fh|
fh.write(<<EOF) fh.write(<<EOF)
+1 -3
View File
@@ -154,8 +154,7 @@ class Generator
end end
def render_toc def render_toc
toc_content = %[<img class="img_block_center" src="rscons_logo_1000.png" />] toc_content = %[<h1>Table of Contents</h1>\n]
toc_content += %[<h1>Table of Contents</h1>\n]
@sections.each do |section| @sections.each do |section|
indent = section.number.split(".").size - 1 indent = section.number.split(".").size - 1
toc_content += %[<span style="padding-left: #{4 * indent}ex;">] toc_content += %[<span style="padding-left: #{4 * indent}ex;">]
@@ -224,6 +223,5 @@ end
input = load_file("doc/user_guide.md") input = load_file("doc/user_guide.md")
FileUtils.rm_rf("gen/user_guide") FileUtils.rm_rf("gen/user_guide")
FileUtils.mkdir_p("gen/user_guide") FileUtils.mkdir_p("gen/user_guide")
FileUtils.cp("img/rscons_logo_1000.png", "gen/user_guide")
Generator.new(input, "gen/user_guide/user_guide.html", false) Generator.new(input, "gen/user_guide/user_guide.html", false)
Generator.new(input, "gen/user_guide", true) Generator.new(input, "gen/user_guide", true)
+133 -470
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -68,7 +68,7 @@ EOF
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("mingw") expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("mingw")
end end
it "returns the number of logical processors that wmic reports" do it "returns the number of logical processors that wmic reports" do
expect(Util).to receive(:`).with("wmic cpu get NumberOfLogicalProcessors -value").and_return("NumberOfLogicalProcessors=7") expect(Util).to receive(:`).with("wmic cpu get NumberOfLogicalProcessors /value").and_return("NumberOfLogicalProcessors=7")
expect(Util.determine_n_threads).to eq(7) expect(Util.determine_n_threads).to eq(7)
end end
end end
+10
View File
@@ -1,5 +1,15 @@
describe Rscons do describe Rscons do
describe ".set_suffix" do
it "changes the suffix to the new one" do
expect(Rscons.set_suffix("foo.c", ".h")).to eq("foo.h")
end
it "appends a suffix if the given file name does not have one" do
expect(Rscons.set_suffix("bazz", ".d")).to eq("bazz.d")
end
end
describe ".get_system_shell" do describe ".get_system_shell" do
before(:each) do before(:each) do
Rscons.instance_variable_set(:@shell, nil) Rscons.instance_variable_set(:@shell, nil)
+6 -6
View File
@@ -1,9 +1,6 @@
if ENV["dist_specs"] require "simplecov"
require_relative "../test/rscons"
else
require "simplecov"
SimpleCov.start do SimpleCov.start do
add_filter "/spec/" add_filter "/spec/"
add_filter "/.bundle/" add_filter "/.bundle/"
if ENV["partial_specs"] if ENV["partial_specs"]
@@ -19,7 +16,10 @@ else
end end
project_name "Rscons" project_name "Rscons"
merge_timeout 3600 merge_timeout 3600
end end
if ENV["dist_specs"]
require_relative "../test/rscons"
else
require "rscons" require "rscons"
end end