Compare commits
44
Commits
v2.0.2
..
f5ab51c477
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5ab51c477 | ||
|
|
b0f2bbb7d5 | ||
|
|
c1dcfa297f | ||
|
|
034dbcd9a6 | ||
|
|
b5d5fe7a7b | ||
|
|
610b8f1266 | ||
|
|
a316c4f922 | ||
|
|
97dbaeb82d | ||
|
|
a2f72c6b87 | ||
|
|
7055cad73c | ||
|
|
4548f4e3c9 | ||
|
|
19dbab3426 | ||
|
|
69f5bea2b2 | ||
|
|
2ee9dda49d | ||
|
|
f011b23499 | ||
|
|
80d52f25b8 | ||
|
|
0face546e3 | ||
|
|
ca747232cd | ||
|
|
a7b46093e9 | ||
|
|
09892eed63 | ||
|
|
117df43f64 | ||
|
|
acc12822b6 | ||
|
|
8c7b43f60c | ||
|
|
7c8becc3f9 | ||
|
|
d1a35501ef | ||
|
|
28a245f0ab | ||
|
|
87a6d9f04f | ||
|
|
556c821cc6 | ||
|
|
441fc9bc65 | ||
|
|
1861874f5c | ||
|
|
6d51c5cbde | ||
|
|
73af83803a | ||
|
|
353f4f45bc | ||
|
|
5bac91f92f | ||
|
|
bbe9563ceb | ||
|
|
5ec74604c6 | ||
|
|
8e06efe61e | ||
|
|
0756874ddb | ||
|
|
dded5e2648 | ||
|
|
fbe60f6ba2 | ||
|
|
8dd9799666 | ||
|
|
f2c755c8bb | ||
|
|
01ca86de8b | ||
|
|
943fabd0d1 |
No files matched your search
@@ -1,3 +1,33 @@
|
|||||||
|
## 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
|
## v2.0.2
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Developing
|
||||||
|
|
||||||
|
# Specs
|
||||||
|
|
||||||
|
To run the rscons specs, the following commands must be available:
|
||||||
|
|
||||||
|
* gcc
|
||||||
|
* clang
|
||||||
|
* g++
|
||||||
|
* clang++
|
||||||
|
* gdc
|
||||||
|
* ldc
|
||||||
|
* flex
|
||||||
|
* bison
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
gem "json"
|
|
||||||
gem "rspec"
|
gem "rspec"
|
||||||
gem "rake"
|
gem "rake"
|
||||||
gem "simplecov"
|
gem "simplecov", "~> 0.15.0"
|
||||||
|
if RbConfig::CONFIG["host"]["msys"]
|
||||||
|
gem "json", "2.1.0"
|
||||||
|
else
|
||||||
|
gem "json"
|
||||||
gem "yard"
|
gem "yard"
|
||||||
gem "rdoc"
|
gem "rdoc"
|
||||||
gem "redcarpet"
|
gem "redcarpet"
|
||||||
gem "syntax"
|
gem "syntax"
|
||||||
|
end
|
||||||
+21
-21
@@ -1,32 +1,32 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
diff-lcs (1.3)
|
diff-lcs (1.4.4)
|
||||||
docile (1.3.2)
|
docile (1.1.5)
|
||||||
json (2.2.0)
|
json (2.5.1)
|
||||||
rake (12.3.2)
|
rake (13.0.6)
|
||||||
rdoc (6.1.1)
|
rdoc (6.3.2)
|
||||||
redcarpet (3.4.0)
|
redcarpet (3.5.1)
|
||||||
rspec (3.8.0)
|
rspec (3.10.0)
|
||||||
rspec-core (~> 3.8.0)
|
rspec-core (~> 3.10.0)
|
||||||
rspec-expectations (~> 3.8.0)
|
rspec-expectations (~> 3.10.0)
|
||||||
rspec-mocks (~> 3.8.0)
|
rspec-mocks (~> 3.10.0)
|
||||||
rspec-core (3.8.2)
|
rspec-core (3.10.1)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-support (~> 3.10.0)
|
||||||
rspec-expectations (3.8.4)
|
rspec-expectations (3.10.1)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-support (~> 3.10.0)
|
||||||
rspec-mocks (3.8.1)
|
rspec-mocks (3.10.2)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-support (~> 3.10.0)
|
||||||
rspec-support (3.8.2)
|
rspec-support (3.10.2)
|
||||||
simplecov (0.15.0)
|
simplecov (0.15.1)
|
||||||
docile (~> 1.1.0)
|
docile (~> 1.1.0)
|
||||||
json (>= 1.8, < 3)
|
json (>= 1.8, < 3)
|
||||||
simplecov-html (~> 0.10.0)
|
simplecov-html (~> 0.10.0)
|
||||||
simplecov-html (0.10.2)
|
simplecov-html (0.10.2)
|
||||||
syntax (1.2.2)
|
syntax (1.2.2)
|
||||||
yard (0.9.20)
|
yard (0.9.26)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
@@ -38,9 +38,9 @@ DEPENDENCIES
|
|||||||
rdoc
|
rdoc
|
||||||
redcarpet
|
redcarpet
|
||||||
rspec
|
rspec
|
||||||
simplecov
|
simplecov (~> 0.15.0)
|
||||||
syntax
|
syntax
|
||||||
yard
|
yard
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.17.3
|
2.1.4
|
||||||
+15
-7
@@ -6,7 +6,6 @@ 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"
|
||||||
|
|
||||||
@@ -18,12 +17,16 @@ task :build_dist do
|
|||||||
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.
|
||||||
@@ -32,16 +35,11 @@ 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"].invoke(args.example_string)
|
Rake::Task["spec"].execute(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")
|
||||||
@@ -88,15 +86,25 @@ EOF
|
|||||||
FileUtils.cp("dist/rscons", "large_project")
|
FileUtils.cp("dist/rscons", "large_project")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
unless RbConfig::CONFIG["host"]["msys"]
|
||||||
|
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
|
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 => [
|
task :all => [
|
||||||
:build_dist,
|
:build_dist,
|
||||||
:spec,
|
:spec,
|
||||||
|
:dspec,
|
||||||
:yard,
|
:yard,
|
||||||
:user_guide,
|
:user_guide,
|
||||||
]
|
]
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
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,3 +1,4 @@
|
|||||||
configure do
|
configure do
|
||||||
|
check_d_compiler
|
||||||
check_d_import "std.stdio"
|
check_d_import "std.stdio"
|
||||||
end
|
end
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
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
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
build do
|
|
||||||
Environment.new do |env|
|
|
||||||
env.Program("program.exe", "program.c")
|
|
||||||
env.Install("install/program.exe", "program.exe")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
int main(int argc, char * argv[])
|
|
||||||
{
|
|
||||||
sleep(2);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
build do
|
||||||
|
sh "echo", "hi there"
|
||||||
|
sh(["echo 1 2"])
|
||||||
|
end
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
build do
|
||||||
|
sh "foobar42"
|
||||||
|
sh "echo", "continued"
|
||||||
|
end
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
build do
|
||||||
|
sh "foobar42", continue: true
|
||||||
|
sh "echo", "continued"
|
||||||
|
end
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "foobar!"
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
exit 42
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "flex!"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
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
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.Program("simple.exe", glob("*.c"))
|
||||||
|
env.Size("simple.size", "simple.exe")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
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
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
configure do
|
||||||
|
rscons "sub/Rsconscript"
|
||||||
|
rscons "sub/Rsconscript2", "configure"
|
||||||
|
puts "top configure"
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
rscons "sub/Rsconscript2", "build"
|
||||||
|
puts "top build"
|
||||||
|
end
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
configure do
|
||||||
|
rscons "sub"
|
||||||
|
rscons "sub", "-f", "Rsconscript2", "configure"
|
||||||
|
puts "top configure"
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
rscons "sub", "-f", "Rsconscript2", "build"
|
||||||
|
puts "top build"
|
||||||
|
end
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
configure do
|
||||||
|
rscons "sub/Rsconscript_fail"
|
||||||
|
puts "top configure"
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
rscons "sub/Rsconscript2", "build"
|
||||||
|
puts "top build"
|
||||||
|
end
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
build do
|
||||||
|
rscons "second", "build"
|
||||||
|
puts "top build"
|
||||||
|
end
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
build do
|
||||||
|
puts "second build"
|
||||||
|
end
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
configure do
|
||||||
|
puts "sub Rsconscript configure"
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
puts "sub Rsconscript build"
|
||||||
|
end
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
configure do
|
||||||
|
puts "sub Rsconscript2 configure"
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
puts "sub Rsconscript2 build"
|
||||||
|
end
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
configure do
|
||||||
|
puts "sub Rsconscript configure"
|
||||||
|
check_program "foobarfailure"
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
puts "sub Rsconscript build"
|
||||||
|
end
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
build do
|
||||||
|
Environment.new(name: "typical") do |env|
|
||||||
|
env["CPPPATH"] += glob("src/**")
|
||||||
|
env.Program("^/typical.exe", glob("src/**/*.c"))
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
build do
|
build do
|
||||||
Environment.new(echo: :command) do |env|
|
Environment.new(echo: :command) do |env|
|
||||||
env.append('CPPPATH' => glob('src/**').sort)
|
env.append("CPPPATH" => glob("src/**"))
|
||||||
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", glob('src/**/*.c') + ["^/one.o"])
|
env.Program("^^/program.exe", ["^/one.o", "^^/two.c"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
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
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
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
|
||||||
+281
-60
@@ -78,10 +78,22 @@ 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...) in a `build` directory.
|
files, dependency files, etc...) and build system metadata in a
|
||||||
|
"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:
|
||||||
@@ -94,7 +106,7 @@ 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 dependency required to run Rscons is to have a Ruby interpreter
|
The only requirement to run Rscons is that the system has 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
|
||||||
@@ -209,6 +221,171 @@ 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.
|
||||||
@@ -246,6 +423,15 @@ 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:
|
||||||
@@ -272,18 +458,6 @@ 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.
|
||||||
@@ -327,18 +501,6 @@ 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.
|
||||||
@@ -387,18 +549,6 @@ 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.
|
||||||
@@ -457,6 +607,46 @@ 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.
|
||||||
@@ -479,21 +669,26 @@ 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 do |env|
|
Environment.new(name: "myproj") do |env|
|
||||||
env.Program("myprog.exe", glob("src/**/*.c"))
|
env.Program("myprog.exe", glob("src/**/*.c"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -501,28 +696,11 @@ 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.
|
||||||
@@ -593,20 +771,33 @@ 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("docs.html", "docs.md",
|
env.Command("user_guide.html", "user_guide.md",
|
||||||
"CMD" => ["pandoc", "-fmarkdown", "-thtml", "-o${_TARGET}", "${_SOURCES}"],
|
"CMD" => ["pandoc", "-fmarkdown", "-thtml", "-o${_TARGET}", "${_SOURCES}"],
|
||||||
"CMD_DESC" => "PANDOC")
|
"CMD_DESC" => "Generating user guide:")
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
||||||
@@ -796,6 +987,36 @@ 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
|
||||||
|
|||||||
+6
-4
@@ -33,10 +33,11 @@ module Rscons
|
|||||||
:Program,
|
:Program,
|
||||||
:SharedLibrary,
|
:SharedLibrary,
|
||||||
:SharedObject,
|
:SharedObject,
|
||||||
|
:Size,
|
||||||
]
|
]
|
||||||
|
|
||||||
# Class to represent a fatal error while building a target.
|
# Class to represent a fatal error during an Rscons operation.
|
||||||
class BuildError < RuntimeError; end
|
class RsconsError < RuntimeError; end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
|
||||||
@@ -81,7 +82,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/
|
elsif Object.const_get("RUBY_PLATFORM") =~ /mingw|msys/
|
||||||
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"]
|
||||||
@@ -102,7 +103,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/
|
if Object.const_get("RUBY_PLATFORM") =~ /mingw|msys/
|
||||||
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"
|
||||||
@@ -146,6 +147,7 @@ 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
@@ -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/
|
if RUBY_PLATFORM =~ /mingw|msys/
|
||||||
(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?
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ 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
|
||||||
@@ -23,6 +27,8 @@ 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
|
||||||
@@ -136,8 +142,8 @@ module Rscons
|
|||||||
env.process
|
env.process
|
||||||
end
|
end
|
||||||
0
|
0
|
||||||
rescue BuildError => be
|
rescue RsconsError => e
|
||||||
Ansi.write($stderr, :red, be.message, :reset, "\n")
|
Ansi.write($stderr, :red, e.message, :reset, "\n")
|
||||||
1
|
1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -171,11 +177,8 @@ 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
|
||||||
if build_dir
|
FileUtils.rm_rf(@build_dir)
|
||||||
FileUtils.rm_rf(build_dir)
|
|
||||||
end
|
|
||||||
cache.clear
|
cache.clear
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
@@ -193,7 +196,10 @@ module Rscons
|
|||||||
co = ConfigureOp.new(options)
|
co = ConfigureOp.new(options)
|
||||||
begin
|
begin
|
||||||
@script.configure(co)
|
@script.configure(co)
|
||||||
rescue ConfigureOp::ConfigureFailure
|
rescue RsconsError => e
|
||||||
|
if e.message and e.message != ""
|
||||||
|
$stderr.puts e.message
|
||||||
|
end
|
||||||
Ansi.write($stderr, :red, "Configuration failed", :reset, "\n")
|
Ansi.write($stderr, :red, "Configuration failed", :reset, "\n")
|
||||||
rv = 1
|
rv = 1
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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]
|
if @vars[:direct] || !@target.start_with?("#{@env.build_root}/")
|
||||||
@env.get_build_fname(target, depfilesuffix, self.class)
|
@env.get_build_fname(@target, depfilesuffix, self.class)
|
||||||
else
|
else
|
||||||
"#{target}#{depfilesuffix}"
|
"#{@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)
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
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
|
||||||
+9
-7
@@ -51,9 +51,6 @@ 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:"
|
||||||
|
|
||||||
@@ -70,6 +67,11 @@ 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]
|
||||||
@@ -84,7 +86,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
|
||||||
|
|
||||||
@@ -100,7 +102,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
|
||||||
@@ -360,9 +362,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"] ||= {}
|
||||||
|
|||||||
+8
-10
@@ -6,11 +6,14 @@ 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
|
||||||
@@ -21,12 +24,7 @@ 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
|
||||||
@@ -58,6 +56,10 @@ 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
|
||||||
@@ -158,10 +160,6 @@ 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
|
||||||
|
|||||||
+40
-47
@@ -5,37 +5,29 @@ 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 = "#{options[:build_dir]}/configure"
|
@work_dir = "#{Rscons.application.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
|
||||||
@@ -62,6 +54,10 @@ 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]
|
||||||
@@ -69,7 +65,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, success_message: cc)
|
complete(cc ? 0 : 1, options.merge(success_message: cc))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a working C++ compiler.
|
# Check for a working C++ compiler.
|
||||||
@@ -80,6 +76,10 @@ 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, success_message: cc)
|
complete(cc ? 0 : 1, options.merge(success_message: cc))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a working D compiler.
|
# Check for a working D compiler.
|
||||||
@@ -98,6 +98,10 @@ 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]
|
||||||
@@ -105,7 +109,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, success_message: dc)
|
complete(dc ? 0 : 1, options.merge(success_message: dc))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a package or configure program output.
|
# Check for a package or configure program output.
|
||||||
@@ -387,11 +391,15 @@ 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
|
||||||
Ansi.write($stdout, :red, "#{fail_message}\n")
|
raise RsconsError.new
|
||||||
raise ConfigureFailure.new
|
|
||||||
else
|
|
||||||
Ansi.write($stdout, :yellow, "#{fail_message}\n")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -408,24 +416,19 @@ 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
|
||||||
#include <stdio.h>
|
int fun(int val) {
|
||||||
int main(int argc, char * argv[]) {
|
return val * 2;
|
||||||
printf("Success.\\n");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
end
|
end
|
||||||
command = %W[#{cc} -o #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.c]
|
command = %W[#{cc} -c -o #{@work_dir}/cfgtest.o #{@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.
|
||||||
#
|
#
|
||||||
@@ -437,25 +440,20 @@ 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
|
||||||
#include <iostream>
|
template<typename T>
|
||||||
using namespace std;
|
T fun(T val) {
|
||||||
int main(int argc, char * argv[]) {
|
return val * 2;
|
||||||
cout << "Success." << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
end
|
end
|
||||||
command = %W[#{cc} -o #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.cxx]
|
command = %W[#{cc} -c -o #{@work_dir}/cfgtest.o #{@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.
|
||||||
#
|
#
|
||||||
@@ -467,9 +465,8 @@ 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 std.stdio;
|
import core.math;
|
||||||
int main() {
|
int fun() {
|
||||||
writeln("Success.");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
@@ -477,32 +474,28 @@ 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} -o #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.d]
|
command = %W[#{dc} -c -o #{@work_dir}/cfgtest.o #{@work_dir}/cfgtest.d]
|
||||||
merge = {"DC" => dc}
|
merge = {"DC" => dc}
|
||||||
when :ldc2
|
when :ldc2
|
||||||
command = %W[#{dc} -of #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.d]
|
# ldc2 on Windows expect an object file suffix of .obj.
|
||||||
|
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| if e == "-o"; "-of"; else; e; end},
|
"DCCMD" => env["DCCMD"].map {|e| e.sub(/^-o$/, "-of")},
|
||||||
"LDCMD" => env["LDCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
|
"LDCMD" => env["LDCMD"].map {|e| e.sub(/^-o$/, "-of")},
|
||||||
"DDEPGEN" => ["-deps=${_DEPFILE}"],
|
"DDEPGEN" => ["-deps=${_DEPFILE}"],
|
||||||
}
|
}
|
||||||
if RUBY_PLATFORM =~ /mingw/
|
merge["OBJSUFFIX"] = [ldc_objsuffix]
|
||||||
# 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,6 +1,6 @@
|
|||||||
module Rscons
|
module Rscons
|
||||||
|
|
||||||
on_windows = RUBY_PLATFORM =~ /mingw|cygwin/
|
on_windows = RUBY_PLATFORM =~ /mingw|msys|cygwin/
|
||||||
pic_flags = on_windows ? [] : %w[-fPIC]
|
pic_flags = on_windows ? [] : %w[-fPIC]
|
||||||
|
|
||||||
# Default Rscons construction variables.
|
# Default Rscons construction variables.
|
||||||
@@ -80,6 +80,9 @@ 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}],
|
||||||
|
|||||||
+22
-16
@@ -1,7 +1,6 @@
|
|||||||
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
|
||||||
@@ -52,6 +51,10 @@ 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]
|
||||||
@@ -59,6 +62,9 @@ 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.
|
||||||
@@ -98,7 +104,8 @@ module Rscons
|
|||||||
else
|
else
|
||||||
:short
|
:short
|
||||||
end
|
end
|
||||||
@build_root = "#{Cache.instance["configuration_data"]["build_dir"]}/e.#{@id}"
|
@name = options[:name] || "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?
|
||||||
@@ -126,14 +133,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]
|
||||||
env = self.class.new(
|
options[:echo] ||= @echo
|
||||||
echo: options[:echo] || @echo,
|
env = self.class.new(options.merge(exclude_builders: true))
|
||||||
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)
|
||||||
@@ -287,9 +294,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 -F to view the failed command log from the previous build operation"
|
msg += "\nUse `#{Util.command_to_execute_me} -F` to view the failed command log from the previous build operation"
|
||||||
end
|
end
|
||||||
raise BuildError.new(msg)
|
raise RsconsError.new(msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -347,12 +354,12 @@ module Rscons
|
|||||||
if target.is_a?(Builder)
|
if target.is_a?(Builder)
|
||||||
target = target.target
|
target = target.target
|
||||||
end
|
end
|
||||||
target = expand_varref(target.to_s)
|
target = expand_path(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_varref(ud)
|
expand_path(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
|
||||||
@@ -468,10 +475,12 @@ module Rscons
|
|||||||
output_fname
|
output_fname
|
||||||
end
|
end
|
||||||
|
|
||||||
# Expand a path to be relative to the Environment's build root.
|
# Expand paths.
|
||||||
#
|
#
|
||||||
# Paths beginning with "^/" are expanded by replacing "^" with the
|
# Paths beginning with "^/" are expanded by replacing "^" with the
|
||||||
# Environment's build root.
|
# Environment's build root (e.g. "build/envname").
|
||||||
|
# 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.
|
||||||
@@ -486,7 +495,7 @@ module Rscons
|
|||||||
expand_path(path)
|
expand_path(path)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
path.sub(%r{^\^(?=[\\/])}, @build_root).gsub("\\", "/")
|
path.sub(%r{^\^\^(?=[\\/])}, Rscons.application.build_dir).sub(%r{^\^(?=[\\/])}, @build_root).gsub("\\", "/")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -702,10 +711,7 @@ module Rscons
|
|||||||
!thread.alive?
|
!thread.alive?
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if @threads.empty?
|
Util.wait_for_thread(*@threads.keys)
|
||||||
raise "No threads to wait for"
|
|
||||||
end
|
|
||||||
ThreadsWait.new(*@threads.keys).next_wait
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+187
-27
@@ -3,32 +3,8 @@ 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
|
||||||
|
|
||||||
# DSL available to the Rsconscript.
|
# Global DSL methods.
|
||||||
class Dsl
|
class 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
|
|
||||||
|
|
||||||
# Return a list of paths matching the specified pattern(s).
|
# Return a list of paths matching the specified pattern(s).
|
||||||
#
|
#
|
||||||
@@ -56,10 +32,194 @@ 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
|
class ConfigureDsl < GlobalDsl
|
||||||
# Create a ConfigureDsl.
|
# Create a ConfigureDsl.
|
||||||
#
|
#
|
||||||
# @param configure_op [ConfigureOp]
|
# @param configure_op [ConfigureOp]
|
||||||
|
|||||||
+42
-5
@@ -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/
|
if RUBY_PLATFORM =~ /mingw|msys/
|
||||||
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 =~ /\s/ ? "'#{c}'" : c }.join(' ')
|
command.map { |c| c[" "] ? "'#{c.gsub("'", "'\\\\''")}'" : 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/
|
when /mswin|mingw|msys/
|
||||||
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,6 +191,40 @@ 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.
|
||||||
@@ -199,11 +233,14 @@ 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/i
|
if RbConfig::CONFIG["host_os"] =~ /mswin|windows|mingw|msys/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,4 +1,4 @@
|
|||||||
module Rscons
|
module Rscons
|
||||||
# Project version.
|
# Project version.
|
||||||
VERSION = "2.0.2"
|
VERSION = "2.3.0"
|
||||||
end
|
end
|
||||||
+7
-4
@@ -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_comments = []
|
stripped = []
|
||||||
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,17 +53,20 @@ 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 heredoc_end or not (line =~ /^\s*(#[^!].*)?$/)
|
if line !~ /#\sspecs/
|
||||||
stripped_comments << line
|
if heredoc_end or line !~ /^\s*(#[^!].*)?$/
|
||||||
|
stripped << line
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
require "zlib"
|
require "zlib"
|
||||||
require "base64"
|
require "base64"
|
||||||
compressed_script = Zlib::Deflate.deflate(stripped_comments.join)
|
compressed_script = Zlib::Deflate.deflate(stripped.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)
|
||||||
|
|||||||
+372
-71
@@ -55,6 +55,8 @@ describe Rscons do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:passenv) {{}}
|
||||||
|
|
||||||
def test_dir(build_test_directory)
|
def test_dir(build_test_directory)
|
||||||
Dir.chdir(@owd)
|
Dir.chdir(@owd)
|
||||||
rm_rf(@build_test_run_dir)
|
rm_rf(@build_test_run_dir)
|
||||||
@@ -118,6 +120,7 @@ describe Rscons do
|
|||||||
command_name = "#{command_prefix}#{@statics[:build_test_id]}"
|
command_name = "#{command_prefix}#{@statics[:build_test_id]}"
|
||||||
File.open("_simplecov_setup.rb", "w") do |fh|
|
File.open("_simplecov_setup.rb", "w") do |fh|
|
||||||
fh.puts <<EOF
|
fh.puts <<EOF
|
||||||
|
unless ENV["dist_specs"]
|
||||||
require "bundler"
|
require "bundler"
|
||||||
Bundler.setup
|
Bundler.setup
|
||||||
require "simplecov"
|
require "simplecov"
|
||||||
@@ -134,6 +137,7 @@ SimpleCov.start do
|
|||||||
end
|
end
|
||||||
formatter(MyFormatter)
|
formatter(MyFormatter)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
# force color off
|
# force color off
|
||||||
ENV["TERM"] = nil
|
ENV["TERM"] = nil
|
||||||
#{options[:ruby_setup_code]}
|
#{options[:ruby_setup_code]}
|
||||||
@@ -143,8 +147,9 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
stdout, stderr, status = nil, nil, nil
|
stdout, stderr, status = nil, nil, nil
|
||||||
Bundler.with_clean_env do
|
Bundler.with_unbundled_env do
|
||||||
env = ENV.to_h
|
env = ENV.to_h
|
||||||
|
env.merge!(passenv)
|
||||||
path = ["#{@build_test_run_dir}/_bin", "#{env["PATH"]}"]
|
path = ["#{@build_test_run_dir}/_bin", "#{env["PATH"]}"]
|
||||||
if options[:path]
|
if options[:path]
|
||||||
path = Array(options[:path]) + path
|
path = Array(options[:path]) + path
|
||||||
@@ -187,6 +192,10 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def nr(str)
|
||||||
|
str.gsub("\r", "")
|
||||||
|
end
|
||||||
|
|
||||||
###########################################################################
|
###########################################################################
|
||||||
# Tests
|
# Tests
|
||||||
###########################################################################
|
###########################################################################
|
||||||
@@ -196,7 +205,24 @@ EOF
|
|||||||
result = run_rscons
|
result = run_rscons
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
|
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
|
||||||
expect(`./simple.exe`).to eq "This is a simple C program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses the build directory specified with -b" do
|
||||||
|
test_dir("simple")
|
||||||
|
result = run_rscons(rscons_args: %w[-b b])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(Dir.exist?("build")).to be_falsey
|
||||||
|
expect(File.exists?("b/e.1/simple.c.o")).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses the build directory specified by an environment variable" do
|
||||||
|
test_dir("simple")
|
||||||
|
passenv["RSCONS_BUILD_DIR"] = "b2"
|
||||||
|
result = run_rscons
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(Dir.exist?("build")).to be_falsey
|
||||||
|
expect(File.exists?("b2/e.1/simple.c.o")).to be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it "allows specifying a Builder object as the source to another build target" do
|
it "allows specifying a Builder object as the source to another build target" do
|
||||||
@@ -204,7 +230,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "builder_as_source.rb")
|
result = run_rscons(rsconscript: "builder_as_source.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?("simple.o")).to be_truthy
|
expect(File.exists?("simple.o")).to be_truthy
|
||||||
expect(`./simple.exe`).to eq "This is a simple C program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'prints commands as they are executed' do
|
it 'prints commands as they are executed' do
|
||||||
@@ -232,18 +258,18 @@ EOF
|
|||||||
result = run_rscons
|
result = run_rscons
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?('build/e.1/header.c.o')).to be_truthy
|
expect(File.exists?('build/e.1/header.c.o')).to be_truthy
|
||||||
expect(`./header.exe`).to eq "The value is 2\n"
|
expect(nr(`./header.exe`)).to eq "The value is 2\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'rebuilds a C module when a header it depends on changes' do
|
it 'rebuilds a C module when a header it depends on changes' do
|
||||||
test_dir('header')
|
test_dir('header')
|
||||||
result = run_rscons
|
result = run_rscons
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(`./header.exe`).to eq "The value is 2\n"
|
expect(nr(`./header.exe`)).to eq "The value is 2\n"
|
||||||
file_sub('header.h') {|line| line.sub(/2/, '5')}
|
file_sub('header.h') {|line| line.sub(/2/, '5')}
|
||||||
result = run_rscons
|
result = run_rscons
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(`./header.exe`).to eq "The value is 5\n"
|
expect(nr(`./header.exe`)).to eq "The value is 5\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not rebuild a C module when its dependencies have not changed' do
|
it 'does not rebuild a C module when its dependencies have not changed' do
|
||||||
@@ -254,7 +280,7 @@ EOF
|
|||||||
%r{Compiling header.c},
|
%r{Compiling header.c},
|
||||||
%r{Linking header.exe},
|
%r{Linking header.exe},
|
||||||
])
|
])
|
||||||
expect(`./header.exe`).to eq "The value is 2\n"
|
expect(nr(`./header.exe`)).to eq "The value is 2\n"
|
||||||
result = run_rscons
|
result = run_rscons
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(result.stdout).to eq ""
|
expect(result.stdout).to eq ""
|
||||||
@@ -268,7 +294,7 @@ EOF
|
|||||||
%r{Compiling header.c},
|
%r{Compiling header.c},
|
||||||
%r{Linking header.exe},
|
%r{Linking header.exe},
|
||||||
])
|
])
|
||||||
expect(`./header.exe`).to eq "The value is 2\n"
|
expect(nr(`./header.exe`)).to eq "The value is 2\n"
|
||||||
sleep 0.05
|
sleep 0.05
|
||||||
file_sub('header.c') {|line| line}
|
file_sub('header.c') {|line| line}
|
||||||
result = run_rscons
|
result = run_rscons
|
||||||
@@ -312,14 +338,14 @@ EOF
|
|||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "expands target and source paths starting with ^/ to be relative to the build root" do
|
it "expands target and source paths starting with ^/ and ^^/" do
|
||||||
test_dir("typical")
|
test_dir("typical")
|
||||||
result = run_rscons(rsconscript: "carat.rb")
|
result = run_rscons(rsconscript: "carat.rb", rscons_args: %w[-b bld])
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
verify_lines(lines(result.stdout), [
|
verify_lines(lines(result.stdout), [
|
||||||
%r{gcc -c -o build/e.1/one.o -MMD -MF build/e.1/one.o.mf -Isrc -Isrc/one -Isrc/two build/e.1/one.c},
|
%r{gcc -c -o bld/e.1/one.o -MMD -MF bld/e.1/one.o.mf -Isrc -Isrc/one -Isrc/two bld/e.1/one.c},
|
||||||
%r{gcc -c -o build/e.1/src/two/two.c.o -MMD -MF build/e.1/src/two/two.c.o.mf -Isrc -Isrc/one -Isrc/two src/two/two.c},
|
%r{gcc -c -o bld/e.1/bld/two.c.o -MMD -MF bld/e.1/bld/two.c.o.mf -Isrc -Isrc/one -Isrc/two bld/two.c},
|
||||||
%r{gcc -o program.exe build/e.1/src/two/two.c.o build/e.1/one.o},
|
%r{gcc -o bld/program.exe bld/e.1/one.o bld/e.1/bld/two.c.o},
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -328,7 +354,7 @@ EOF
|
|||||||
result = run_rscons
|
result = run_rscons
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?('foo.yml')).to be_truthy
|
expect(File.exists?('foo.yml')).to be_truthy
|
||||||
expect(IO.read('foo.yml')).to eq("---\nkey: value\n")
|
expect(nr(IO.read('foo.yml'))).to eq("---\nkey: value\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises an error when a side-effect file is registered for a build target that is not registered" do
|
it "raises an error when a side-effect file is registered for a build target that is not registered" do
|
||||||
@@ -337,20 +363,6 @@ EOF
|
|||||||
expect(result.stderr).to match /Could not find a registered build target "foo"/
|
expect(result.stderr).to match /Could not find a registered build target "foo"/
|
||||||
end
|
end
|
||||||
|
|
||||||
it "allows replacing a running executable when performing an 'install' operation" do
|
|
||||||
test_dir("install_running_exe")
|
|
||||||
result = run_rscons(op: "install")
|
|
||||||
expect(result.stderr).to eq ""
|
|
||||||
fcontents = File.read("program.c", mode: "rb")
|
|
||||||
File.open("program.c", "wb") do |fh|
|
|
||||||
fh.write(fcontents.sub(/2/, '3'))
|
|
||||||
end
|
|
||||||
pid = Process.spawn("install/program.exe")
|
|
||||||
result = run_rscons(op: "install")
|
|
||||||
expect(result.stderr).to eq ""
|
|
||||||
Process.wait(pid)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "clean operation" do
|
context "clean operation" do
|
||||||
it 'cleans built files' do
|
it 'cleans built files' do
|
||||||
test_dir("simple")
|
test_dir("simple")
|
||||||
@@ -428,7 +440,7 @@ EOF
|
|||||||
%r{Linking program.exe},
|
%r{Linking program.exe},
|
||||||
])
|
])
|
||||||
expect(File.exists?('inc.h')).to be_truthy
|
expect(File.exists?('inc.h')).to be_truthy
|
||||||
expect(`./program.exe`).to eq "The value is 5678\n"
|
expect(nr(`./program.exe`)).to eq "The value is 5678\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'supports custom builders with multiple targets' do
|
it 'supports custom builders with multiple targets' do
|
||||||
@@ -444,13 +456,13 @@ EOF
|
|||||||
])
|
])
|
||||||
expect(File.exists?("inc.c")).to be_truthy
|
expect(File.exists?("inc.c")).to be_truthy
|
||||||
expect(File.exists?("inc.h")).to be_truthy
|
expect(File.exists?("inc.h")).to be_truthy
|
||||||
expect(`./program.exe`).to eq "The value is 42\n"
|
expect(nr(`./program.exe`)).to eq "The value is 42\n"
|
||||||
|
|
||||||
File.open("inc.c", "w") {|fh| fh.puts "int THE_VALUE = 33;"}
|
File.open("inc.c", "w") {|fh| fh.puts "int THE_VALUE = 33;"}
|
||||||
result = run_rscons(rsconscript: "multiple_targets.rb")
|
result = run_rscons(rsconscript: "multiple_targets.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
verify_lines(lines(result.stdout), [%r{CHGen inc.c}])
|
verify_lines(lines(result.stdout), [%r{CHGen inc.c}])
|
||||||
expect(`./program.exe`).to eq "The value is 42\n"
|
expect(nr(`./program.exe`)).to eq "The value is 42\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises an error when a custom builder returns an invalid value from #run' do
|
it 'raises an error when a custom builder returns an invalid value from #run' do
|
||||||
@@ -518,7 +530,7 @@ EOF
|
|||||||
result = run_rscons
|
result = run_rscons
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?('build/e.1/simple.cc.o')).to be_truthy
|
expect(File.exists?('build/e.1/simple.cc.o')).to be_truthy
|
||||||
expect(`./simple.exe`).to eq "This is a simple C++ program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C++ program\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "links with the C++ linker when object files were built from C++ sources" do
|
it "links with the C++ linker when object files were built from C++ sources" do
|
||||||
@@ -526,7 +538,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "link_objects.rb")
|
result = run_rscons(rsconscript: "link_objects.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?("simple.o")).to be_truthy
|
expect(File.exists?("simple.o")).to be_truthy
|
||||||
expect(`./simple.exe`).to eq "This is a simple C++ program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C++ program\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'allows overriding construction variables for individual builder calls' do
|
it 'allows overriding construction variables for individual builder calls' do
|
||||||
@@ -534,12 +546,12 @@ EOF
|
|||||||
result = run_rscons
|
result = run_rscons
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
verify_lines(lines(result.stdout), [
|
verify_lines(lines(result.stdout), [
|
||||||
%r{gcc -c -o one.o -MMD -MF one.o.mf -DONE one.c},
|
%r{gcc -c -o one.o -MMD -MF build/e.1/one.o.mf -DONE one.c},
|
||||||
%r{gcc -c -o build/e.1/two.c.o -MMD -MF build/e.1/two.c.o.mf two.c},
|
%r{gcc -c -o build/e.1/two.c.o -MMD -MF build/e.1/two.c.o.mf two.c},
|
||||||
%r{gcc -o two_sources.exe one.o build/e.1/two.c.o},
|
%r{gcc -o two_sources.exe one.o build/e.1/two.c.o},
|
||||||
])
|
])
|
||||||
expect(File.exists?("two_sources.exe")).to be_truthy
|
expect(File.exists?("two_sources.exe")).to be_truthy
|
||||||
expect(`./two_sources.exe`).to eq "This is a C program with two sources.\n"
|
expect(nr(`./two_sources.exe`)).to eq "This is a C program with two sources.\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'builds a static library archive' do
|
it 'builds a static library archive' do
|
||||||
@@ -554,7 +566,7 @@ EOF
|
|||||||
%r{gcc -o library.exe lib.a build/e.1/three.c.o},
|
%r{gcc -o library.exe lib.a build/e.1/three.c.o},
|
||||||
])
|
])
|
||||||
expect(File.exists?("library.exe")).to be_truthy
|
expect(File.exists?("library.exe")).to be_truthy
|
||||||
expect(`ar t lib.a`).to eq "one.c.o\ntwo.c.o\n"
|
expect(nr(`ar t lib.a`)).to eq "one.c.o\ntwo.c.o\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'supports build hooks to override construction variables' do
|
it 'supports build hooks to override construction variables' do
|
||||||
@@ -566,7 +578,7 @@ EOF
|
|||||||
%r{gcc -c -o build/e.1/src/two/two.c.o -MMD -MF build/e.1/src/two/two.c.o.mf -Isrc/one -Isrc/two -O2 src/two/two.c},
|
%r{gcc -c -o build/e.1/src/two/two.c.o -MMD -MF build/e.1/src/two/two.c.o.mf -Isrc/one -Isrc/two -O2 src/two/two.c},
|
||||||
%r{gcc -o build_hook.exe build/e.1/src/one/one.c.o build/e.1/src/two/two.c.o},
|
%r{gcc -o build_hook.exe build/e.1/src/one/one.c.o build/e.1/src/two/two.c.o},
|
||||||
])
|
])
|
||||||
expect(`./build_hook.exe`).to eq "Hello from two()\n"
|
expect(nr(`./build_hook.exe`)).to eq "Hello from two()\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'supports build hooks to override the entire vars hash' do
|
it 'supports build hooks to override the entire vars hash' do
|
||||||
@@ -574,8 +586,8 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "build_hooks_override_vars.rb")
|
result = run_rscons(rsconscript: "build_hooks_override_vars.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
verify_lines(lines(result.stdout), [
|
verify_lines(lines(result.stdout), [
|
||||||
%r{gcc -c -o one.o -MMD -MF one.o.mf -Isrc -Isrc/one -Isrc/two -O1 src/two/two.c},
|
%r{gcc -c -o one.o -MMD -MF build/e.1/one.o.mf -Isrc -Isrc/one -Isrc/two -O1 src/two/two.c},
|
||||||
%r{gcc -c -o two.o -MMD -MF two.o.mf -Isrc -Isrc/one -Isrc/two -O2 src/two/two.c},
|
%r{gcc -c -o two.o -MMD -MF build/e.1/two.o.mf -Isrc -Isrc/one -Isrc/two -O2 src/two/two.c},
|
||||||
])
|
])
|
||||||
expect(File.exists?('one.o')).to be_truthy
|
expect(File.exists?('one.o')).to be_truthy
|
||||||
expect(File.exists?('two.o')).to be_truthy
|
expect(File.exists?('two.o')).to be_truthy
|
||||||
@@ -592,7 +604,7 @@ EOF
|
|||||||
%r{Linking simple.exe},
|
%r{Linking simple.exe},
|
||||||
])
|
])
|
||||||
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
|
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
|
||||||
expect(`./simple.exe`).to eq "This is a simple C program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
|
||||||
|
|
||||||
File.open("program.ld", "w") {|fh| fh.puts("2")}
|
File.open("program.ld", "w") {|fh| fh.puts("2")}
|
||||||
result = run_rscons(rsconscript: "user_dependencies.rb")
|
result = run_rscons(rsconscript: "user_dependencies.rb")
|
||||||
@@ -609,6 +621,28 @@ EOF
|
|||||||
expect(result.stdout).to eq ""
|
expect(result.stdout).to eq ""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "rebuilds when user-specified dependencies using ^ change" do
|
||||||
|
test_dir("simple")
|
||||||
|
|
||||||
|
passenv["file_contents"] = "1"
|
||||||
|
result = run_rscons(rsconscript: "user_dependencies_carat.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
%r{Compiling simple.c},
|
||||||
|
%r{Linking .*simple.exe},
|
||||||
|
])
|
||||||
|
|
||||||
|
passenv["file_contents"] = "2"
|
||||||
|
result = run_rscons(rsconscript: "user_dependencies_carat.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
verify_lines(lines(result.stdout), [%r{Linking .*simple.exe}])
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "user_dependencies_carat.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.stdout).to eq ""
|
||||||
|
end
|
||||||
|
|
||||||
|
unless RUBY_PLATFORM =~ /mingw|msys/
|
||||||
it "supports building D sources with gdc" do
|
it "supports building D sources with gdc" do
|
||||||
test_dir("d")
|
test_dir("d")
|
||||||
result = run_rscons
|
result = run_rscons
|
||||||
@@ -619,14 +653,15 @@ EOF
|
|||||||
verify_lines(slines, [%r{gdc -o hello-d.exe build/e.1/main.d.o build/e.1/mod.d.o}])
|
verify_lines(slines, [%r{gdc -o hello-d.exe build/e.1/main.d.o build/e.1/mod.d.o}])
|
||||||
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
|
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "supports building D sources with ldc2" do
|
it "supports building D sources with ldc2" do
|
||||||
test_dir("d")
|
test_dir("d")
|
||||||
result = run_rscons(rsconscript: "build-ldc2.rb")
|
result = run_rscons(rsconscript: "build-ldc2.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
slines = lines(result.stdout)
|
slines = lines(result.stdout)
|
||||||
verify_lines(slines, [%r{ldc2 -c -of build/e.1/main.d.o(bj)? -deps=build/e.1/main.d.o.mf main.d}])
|
verify_lines(slines, [%r{ldc2 -c -of build/e.1/main.d.o(bj)? -deps=build/e.1/main.d.o(bj)?.mf main.d}])
|
||||||
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o.mf mod.d}])
|
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o(bj)?.mf mod.d}])
|
||||||
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/e.1/main.d.o(bj)? build/e.1/mod.d.o(bj)?}])
|
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/e.1/main.d.o(bj)? build/e.1/mod.d.o(bj)?}])
|
||||||
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
|
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
|
||||||
end
|
end
|
||||||
@@ -636,8 +671,8 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "build-ldc2.rb")
|
result = run_rscons(rsconscript: "build-ldc2.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
slines = lines(result.stdout)
|
slines = lines(result.stdout)
|
||||||
verify_lines(slines, [%r{ldc2 -c -of build/e.1/main.d.o(bj)? -deps=build/e.1/main.d.o.mf main.d}])
|
verify_lines(slines, [%r{ldc2 -c -of build/e.1/main.d.o(bj)? -deps=build/e.1/main.d.o(bj)?.mf main.d}])
|
||||||
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o.mf mod.d}])
|
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o(bj)?.mf mod.d}])
|
||||||
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/e.1/main.d.o(bj)? build/e.1/mod.d.o(bj)?}])
|
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/e.1/main.d.o(bj)? build/e.1/mod.d.o(bj)?}])
|
||||||
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
|
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
|
||||||
contents = File.read("mod.d", mode: "rb").sub("42", "33")
|
contents = File.read("mod.d", mode: "rb").sub("42", "33")
|
||||||
@@ -647,13 +682,13 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "build-ldc2.rb")
|
result = run_rscons(rsconscript: "build-ldc2.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
slines = lines(result.stdout)
|
slines = lines(result.stdout)
|
||||||
verify_lines(slines, [%r{ldc2 -c -of build/e.1/main.d.o(bj)? -deps=build/e.1/main.d.o.mf main.d}])
|
verify_lines(slines, [%r{ldc2 -c -of build/e.1/main.d.o(bj)? -deps=build/e.1/main.d.o(bj)?.mf main.d}])
|
||||||
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o.mf mod.d}])
|
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o(bj)?.mf mod.d}])
|
||||||
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/e.1/main.d.o(bj)? build/e.1/mod.d.o(bj)?}])
|
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/e.1/main.d.o(bj)? build/e.1/mod.d.o(bj)?}])
|
||||||
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 33!"
|
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 33!"
|
||||||
end
|
end
|
||||||
|
|
||||||
unless ENV["omit_gdc_tests"]
|
unless RUBY_PLATFORM =~ /mingw|msys/
|
||||||
it "links with the D linker when object files were built from D sources" do
|
it "links with the D linker when object files were built from D sources" do
|
||||||
test_dir("d")
|
test_dir("d")
|
||||||
result = run_rscons(rsconscript: "link_objects.rb")
|
result = run_rscons(rsconscript: "link_objects.rb")
|
||||||
@@ -689,7 +724,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "shared_library_d.rb")
|
result = run_rscons(rsconscript: "shared_library_d.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
slines = lines(result.stdout)
|
slines = lines(result.stdout)
|
||||||
if RUBY_PLATFORM =~ /mingw/
|
if RUBY_PLATFORM =~ /mingw|msys/
|
||||||
verify_lines(slines, [%r{Linking mine.dll}])
|
verify_lines(slines, [%r{Linking mine.dll}])
|
||||||
else
|
else
|
||||||
verify_lines(slines, [%r{Linking libmine.so}])
|
verify_lines(slines, [%r{Linking libmine.so}])
|
||||||
@@ -715,7 +750,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "preprocess.rb")
|
result = run_rscons(rsconscript: "preprocess.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.read("simplepp.c")).to match /# \d+ "simple.c"/
|
expect(File.read("simplepp.c")).to match /# \d+ "simple.c"/
|
||||||
expect(`./simple.exe`).to eq "This is a simple C program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports preprocessing C++ sources" do
|
it "supports preprocessing C++ sources" do
|
||||||
@@ -723,7 +758,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "preprocess.rb")
|
result = run_rscons(rsconscript: "preprocess.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.read("simplepp.cc")).to match /# \d+ "simple.cc"/
|
expect(File.read("simplepp.cc")).to match /# \d+ "simple.cc"/
|
||||||
expect(`./simple.exe`).to eq "This is a simple C++ program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C++ program\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports invoking builders with no sources" do
|
it "supports invoking builders with no sources" do
|
||||||
@@ -741,14 +776,14 @@ EOF
|
|||||||
%r{Linking program.exe},
|
%r{Linking program.exe},
|
||||||
])
|
])
|
||||||
expect(File.exists?('inc.h')).to be_truthy
|
expect(File.exists?('inc.h')).to be_truthy
|
||||||
expect(`./program.exe`).to eq "The value is 678\n"
|
expect(nr(`./program.exe`)).to eq "The value is 678\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports lambdas as construction variable values" do
|
it "supports lambdas as construction variable values" do
|
||||||
test_dir "custom_builder"
|
test_dir "custom_builder"
|
||||||
result = run_rscons(rsconscript: "cvar_lambda.rb")
|
result = run_rscons(rsconscript: "cvar_lambda.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(`./program.exe`).to eq "The value is 5678\n"
|
expect(nr(`./program.exe`)).to eq "The value is 5678\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports registering build targets from within a build hook" do
|
it "supports registering build targets from within a build hook" do
|
||||||
@@ -757,7 +792,7 @@ EOF
|
|||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?("build/e.1/simple.c.o")).to be_truthy
|
expect(File.exists?("build/e.1/simple.c.o")).to be_truthy
|
||||||
expect(File.exists?("build/e.1/simple.c.o.txt")).to be_truthy
|
expect(File.exists?("build/e.1/simple.c.o.txt")).to be_truthy
|
||||||
expect(`./simple.exe`).to eq "This is a simple C program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports multiple values for CXXSUFFIX" do
|
it "supports multiple values for CXXSUFFIX" do
|
||||||
@@ -767,7 +802,7 @@ EOF
|
|||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?("build/e.1/simple.cc.o")).to be_truthy
|
expect(File.exists?("build/e.1/simple.cc.o")).to be_truthy
|
||||||
expect(File.exists?("build/e.1/other.cccc.o")).to be_truthy
|
expect(File.exists?("build/e.1/other.cccc.o")).to be_truthy
|
||||||
expect(`./simple.exe`).to eq "This is a simple C++ program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C++ program\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports multiple values for CSUFFIX" do
|
it "supports multiple values for CSUFFIX" do
|
||||||
@@ -777,7 +812,7 @@ EOF
|
|||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?("build/e.1/src/one/one.yargh.o")).to be_truthy
|
expect(File.exists?("build/e.1/src/one/one.yargh.o")).to be_truthy
|
||||||
expect(File.exists?("build/e.1/src/two/two.c.o")).to be_truthy
|
expect(File.exists?("build/e.1/src/two/two.c.o")).to be_truthy
|
||||||
expect(`./program.exe`).to eq "Hello from two()\n"
|
expect(nr(`./program.exe`)).to eq "Hello from two()\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports multiple values for OBJSUFFIX" do
|
it "supports multiple values for OBJSUFFIX" do
|
||||||
@@ -787,7 +822,7 @@ EOF
|
|||||||
expect(File.exists?("two_sources.exe")).to be_truthy
|
expect(File.exists?("two_sources.exe")).to be_truthy
|
||||||
expect(File.exists?("one.oooo")).to be_truthy
|
expect(File.exists?("one.oooo")).to be_truthy
|
||||||
expect(File.exists?("two.ooo")).to be_truthy
|
expect(File.exists?("two.ooo")).to be_truthy
|
||||||
expect(`./two_sources.exe`).to eq "This is a C program with two sources.\n"
|
expect(nr(`./two_sources.exe`)).to eq "This is a C program with two sources.\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports multiple values for LIBSUFFIX" do
|
it "supports multiple values for LIBSUFFIX" do
|
||||||
@@ -795,7 +830,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "libsuffix.rb")
|
result = run_rscons(rsconscript: "libsuffix.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?("two_sources.exe")).to be_truthy
|
expect(File.exists?("two_sources.exe")).to be_truthy
|
||||||
expect(`./two_sources.exe`).to eq "This is a C program with two sources.\n"
|
expect(nr(`./two_sources.exe`)).to eq "This is a C program with two sources.\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports multiple values for ASSUFFIX" do
|
it "supports multiple values for ASSUFFIX" do
|
||||||
@@ -810,7 +845,7 @@ EOF
|
|||||||
%r{Linking two_sources.exe},
|
%r{Linking two_sources.exe},
|
||||||
])
|
])
|
||||||
expect(File.exists?("two_sources.exe")).to be_truthy
|
expect(File.exists?("two_sources.exe")).to be_truthy
|
||||||
expect(`./two_sources.exe`).to eq "This is a C program with two sources.\n"
|
expect(nr(`./two_sources.exe`)).to eq "This is a C program with two sources.\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports dumping an Environment's construction variables" do
|
it "supports dumping an Environment's construction variables" do
|
||||||
@@ -849,7 +884,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "cvar_array.rb")
|
result = run_rscons(rsconscript: "cvar_array.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(File.exists?("build/e.1/simple.c.o")).to be_truthy
|
expect(File.exists?("build/e.1/simple.c.o")).to be_truthy
|
||||||
expect(`./simple.exe`).to eq "This is a simple C program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports registering multiple build targets with the same target path" do
|
it "supports registering multiple build targets with the same target path" do
|
||||||
@@ -940,7 +975,7 @@ EOF
|
|||||||
result = run_rscons
|
result = run_rscons
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
slines = lines(result.stdout)
|
slines = lines(result.stdout)
|
||||||
if RUBY_PLATFORM =~ /mingw/
|
if RUBY_PLATFORM =~ /mingw|msys/
|
||||||
verify_lines(slines, [%r{Linking mine.dll}])
|
verify_lines(slines, [%r{Linking mine.dll}])
|
||||||
expect(File.exists?("mine.dll")).to be_truthy
|
expect(File.exists?("mine.dll")).to be_truthy
|
||||||
else
|
else
|
||||||
@@ -952,7 +987,7 @@ EOF
|
|||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(result.stdout).to eq ""
|
expect(result.stdout).to eq ""
|
||||||
|
|
||||||
ld_library_path_prefix = (RUBY_PLATFORM =~ /mingw/ ? "" : "LD_LIBRARY_PATH=. ")
|
ld_library_path_prefix = (RUBY_PLATFORM =~ /mingw|msys/ ? "" : "LD_LIBRARY_PATH=. ")
|
||||||
expect(`#{ld_library_path_prefix}./test-shared.exe`).to match /Hi from one/
|
expect(`#{ld_library_path_prefix}./test-shared.exe`).to match /Hi from one/
|
||||||
expect(`./test-static.exe`).to match /Hi from one/
|
expect(`./test-static.exe`).to match /Hi from one/
|
||||||
end
|
end
|
||||||
@@ -971,7 +1006,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "shared_library_cxx.rb")
|
result = run_rscons(rsconscript: "shared_library_cxx.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
slines = lines(result.stdout)
|
slines = lines(result.stdout)
|
||||||
if RUBY_PLATFORM =~ /mingw/
|
if RUBY_PLATFORM =~ /mingw|msys/
|
||||||
verify_lines(slines, [%r{Linking mine.dll}])
|
verify_lines(slines, [%r{Linking mine.dll}])
|
||||||
else
|
else
|
||||||
verify_lines(slines, [%r{Linking libmine.so}])
|
verify_lines(slines, [%r{Linking libmine.so}])
|
||||||
@@ -981,7 +1016,7 @@ EOF
|
|||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(result.stdout).to eq ""
|
expect(result.stdout).to eq ""
|
||||||
|
|
||||||
ld_library_path_prefix = (RUBY_PLATFORM =~ /mingw/ ? "" : "LD_LIBRARY_PATH=. ")
|
ld_library_path_prefix = (RUBY_PLATFORM =~ /mingw|msys/ ? "" : "LD_LIBRARY_PATH=. ")
|
||||||
expect(`#{ld_library_path_prefix}./test-shared.exe`).to match /Hi from one/
|
expect(`#{ld_library_path_prefix}./test-shared.exe`).to match /Hi from one/
|
||||||
expect(`./test-static.exe`).to match /Hi from one/
|
expect(`./test-static.exe`).to match /Hi from one/
|
||||||
end
|
end
|
||||||
@@ -1048,7 +1083,7 @@ EOF
|
|||||||
|
|
||||||
result = run_rscons
|
result = run_rscons
|
||||||
expect(result.stderr).to match /Failed to build/
|
expect(result.stderr).to match /Failed to build/
|
||||||
expect(result.stderr).to match /^Use.*-F.*to view the failed command log/
|
expect(result.stderr).to match %r{^Use .*/rscons(\.rb)? -F.*to view the failed command log}
|
||||||
expect(result.status).to_not eq 0
|
expect(result.status).to_not eq 0
|
||||||
|
|
||||||
result = run_rscons(rscons_args: %w[-F])
|
result = run_rscons(rscons_args: %w[-F])
|
||||||
@@ -1058,6 +1093,23 @@ EOF
|
|||||||
expect(result.status).to eq 0
|
expect(result.status).to eq 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "stores build artifacts in a directory according to Environment name" do
|
||||||
|
test_dir "typical"
|
||||||
|
|
||||||
|
result = run_rscons
|
||||||
|
expect(File.exist?("build/typical/typical.exe")).to be_truthy
|
||||||
|
expect(File.exist?("build/typical/src/one/one.c.o")).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
it "names Environment during clone" do
|
||||||
|
test_dir "typical"
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "clone_and_name.rb")
|
||||||
|
expect(File.exist?("build/typical/typical.exe")).to be_truthy
|
||||||
|
expect(File.exist?("build/typical/src/one/one.c.o")).to be_truthy
|
||||||
|
expect(Dir.exist?("build/e.1")).to be_falsey
|
||||||
|
end
|
||||||
|
|
||||||
context "colored output" do
|
context "colored output" do
|
||||||
it "does not output in color with --color=off" do
|
it "does not output in color with --color=off" do
|
||||||
test_dir("simple")
|
test_dir("simple")
|
||||||
@@ -1112,7 +1164,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "command_builder.rb")
|
result = run_rscons(rsconscript: "command_builder.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
verify_lines(lines(result.stdout), [%r{BuildIt simple.exe}])
|
verify_lines(lines(result.stdout), [%r{BuildIt simple.exe}])
|
||||||
expect(`./simple.exe`).to eq "This is a simple C program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
|
||||||
|
|
||||||
result = run_rscons(rsconscript: "command_builder.rb")
|
result = run_rscons(rsconscript: "command_builder.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
@@ -1278,7 +1330,8 @@ EOF
|
|||||||
context "Cache management" do
|
context "Cache management" do
|
||||||
it "prints a warning when the cache is corrupt" do
|
it "prints a warning when the cache is corrupt" do
|
||||||
test_dir("simple")
|
test_dir("simple")
|
||||||
File.open(Rscons::Cache::CACHE_FILE, "w") do |fh|
|
FileUtils.mkdir("build")
|
||||||
|
File.open("build/.rsconscache", "w") do |fh|
|
||||||
fh.puts("[1]")
|
fh.puts("[1]")
|
||||||
end
|
end
|
||||||
result = run_rscons
|
result = run_rscons
|
||||||
@@ -1457,6 +1510,25 @@ EOF
|
|||||||
expect(result.status).to eq 0
|
expect(result.status).to eq 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "allows prepending and appending to PATH" do
|
||||||
|
test_dir "simple"
|
||||||
|
result = run_rscons(rsconscript: "pathing.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.stdout).to match /flex!/
|
||||||
|
expect(result.stdout).to match /foobar!/
|
||||||
|
expect(File.exist?("simple.o")).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
it "writes the dependency file to the build root" do
|
||||||
|
test_dir "simple"
|
||||||
|
result = run_rscons(rsconscript: "distclean.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.stdout).to match /Compiling simple\.c/
|
||||||
|
expect(File.exist?("simple.o")).to be_truthy
|
||||||
|
expect(File.exist?("simple.o.mf")).to be_falsey
|
||||||
|
expect(File.exist?("build/e.1/simple.o.mf")).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
context "debugging" do
|
context "debugging" do
|
||||||
it "prints a message when the target does not exist" do
|
it "prints a message when the target does not exist" do
|
||||||
test_dir("simple")
|
test_dir("simple")
|
||||||
@@ -1550,7 +1622,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "override_depfilesuffix.rb")
|
result = run_rscons(rsconscript: "override_depfilesuffix.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
verify_lines(lines(result.stdout), [
|
verify_lines(lines(result.stdout), [
|
||||||
%r{gcc -c -o simple.o -MMD -MF simple.o.deppy simple.c},
|
%r{gcc -c -o simple.o -MMD -MF build/e.1/simple.o.deppy simple.c},
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1593,7 +1665,7 @@ EOF
|
|||||||
result = run_rscons(rsconscript: "shared_library_set_shld.rb")
|
result = run_rscons(rsconscript: "shared_library_set_shld.rb")
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
slines = lines(result.stdout)
|
slines = lines(result.stdout)
|
||||||
if RUBY_PLATFORM =~ /mingw/
|
if RUBY_PLATFORM =~ /mingw|msys/
|
||||||
verify_lines(slines, [%r{Linking mine.dll}])
|
verify_lines(slines, [%r{Linking mine.dll}])
|
||||||
else
|
else
|
||||||
verify_lines(slines, [%r{Linking libmine.so}])
|
verify_lines(slines, [%r{Linking libmine.so}])
|
||||||
@@ -1608,6 +1680,21 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "Size builder" do
|
||||||
|
it "generates a size file" do
|
||||||
|
test_dir "simple"
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "size.rb")
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
/Linking .*simple\.exe/,
|
||||||
|
/Size .*simple\.exe .*simple\.size/,
|
||||||
|
])
|
||||||
|
expect(File.exist?("simple.exe")).to be_truthy
|
||||||
|
expect(File.exist?("simple.size")).to be_truthy
|
||||||
|
expect(File.read("simple.size")).to match /text.*data.*bss/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "multi-threading" do
|
context "multi-threading" do
|
||||||
it "waits for subcommands in threads for builders that support threaded commands" do
|
it "waits for subcommands in threads for builders that support threaded commands" do
|
||||||
test_dir("simple")
|
test_dir("simple")
|
||||||
@@ -1711,6 +1798,22 @@ EOF
|
|||||||
expect(result.status).to_not eq 0
|
expect(result.status).to_not eq 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "automatically runs the configure operation if the project is not yet configured in the given build directory" do
|
||||||
|
test_dir "configure"
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "check_c_compiler.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
expect(result.stdout).to match /Checking for C compiler\.\.\./
|
||||||
|
expect(Dir.exist?("build/_configure")).to be_truthy
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "check_c_compiler.rb", rscons_args: %w[--build=bb])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
expect(result.stdout).to match /Checking for C compiler\.\.\./
|
||||||
|
expect(Dir.exist?("bb/_configure")).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
context "check_c_compiler" do
|
context "check_c_compiler" do
|
||||||
{"check_c_compiler.rb" => "when no arguments are given",
|
{"check_c_compiler.rb" => "when no arguments are given",
|
||||||
"check_c_compiler_find_first.rb" => "when arguments are given"}.each_pair do |rsconscript, desc|
|
"check_c_compiler_find_first.rb" => "when arguments are given"}.each_pair do |rsconscript, desc|
|
||||||
@@ -1801,6 +1904,7 @@ EOF
|
|||||||
{"check_d_compiler.rb" => "when no arguments are given",
|
{"check_d_compiler.rb" => "when no arguments are given",
|
||||||
"check_d_compiler_find_first.rb" => "when arguments are given"}.each_pair do |rsconscript, desc|
|
"check_d_compiler_find_first.rb" => "when arguments are given"}.each_pair do |rsconscript, desc|
|
||||||
context desc do
|
context desc do
|
||||||
|
unless RUBY_PLATFORM =~ /mingw|msys/
|
||||||
it "finds the first listed D compiler" do
|
it "finds the first listed D compiler" do
|
||||||
test_dir "configure"
|
test_dir "configure"
|
||||||
result = run_rscons(rsconscript: rsconscript, op: "configure")
|
result = run_rscons(rsconscript: rsconscript, op: "configure")
|
||||||
@@ -1808,6 +1912,7 @@ EOF
|
|||||||
expect(result.status).to eq 0
|
expect(result.status).to eq 0
|
||||||
expect(result.stdout).to match /Checking for D compiler\.\.\. gdc/
|
expect(result.stdout).to match /Checking for D compiler\.\.\. gdc/
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "finds the second listed D compiler" do
|
it "finds the second listed D compiler" do
|
||||||
test_dir "configure"
|
test_dir "configure"
|
||||||
@@ -1830,6 +1935,7 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
unless RUBY_PLATFORM =~ /mingw|msys/
|
||||||
it "successfully tests a compiler with an unknown name that uses gdc-compatible options" do
|
it "successfully tests a compiler with an unknown name that uses gdc-compatible options" do
|
||||||
test_dir "configure"
|
test_dir "configure"
|
||||||
create_exe "mycompiler", %[exec gdc "$@"]
|
create_exe "mycompiler", %[exec gdc "$@"]
|
||||||
@@ -1838,6 +1944,7 @@ EOF
|
|||||||
expect(result.status).to eq 0
|
expect(result.status).to eq 0
|
||||||
expect(result.stdout).to match /Checking for D compiler\.\.\. mycompiler/
|
expect(result.stdout).to match /Checking for D compiler\.\.\. mycompiler/
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "successfully tests a compiler with an unknown name that uses ldc2-compatible options" do
|
it "successfully tests a compiler with an unknown name that uses ldc2-compatible options" do
|
||||||
test_dir "configure"
|
test_dir "configure"
|
||||||
@@ -2226,6 +2333,16 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "on_fail option" do
|
||||||
|
it "prints on_fail messages and calls on_fail procs on failure" do
|
||||||
|
test_dir "configure"
|
||||||
|
result = run_rscons(rsconscript: "on_fail.rb", op: %w[configure])
|
||||||
|
expect(result.status).to_not eq 0
|
||||||
|
expect(result.stdout).to match /Install the foo123 package/
|
||||||
|
expect(result.stdout).to match /Install the foo123cxx package/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "does everything" do
|
it "does everything" do
|
||||||
test_dir "configure"
|
test_dir "configure"
|
||||||
create_exe "pkg-config", "echo '-DMYPACKAGE'"
|
create_exe "pkg-config", "echo '-DMYPACKAGE'"
|
||||||
@@ -2233,7 +2350,6 @@ EOF
|
|||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(result.status).to eq 0
|
expect(result.status).to eq 0
|
||||||
expect(result.stdout).to match /Configuring configure test\.\.\./
|
expect(result.stdout).to match /Configuring configure test\.\.\./
|
||||||
expect(result.stdout).to match /Setting build directory\.\.\. bb/
|
|
||||||
expect(result.stdout).to match %r{Setting prefix\.\.\. /my/prefix}
|
expect(result.stdout).to match %r{Setting prefix\.\.\. /my/prefix}
|
||||||
expect(result.stdout).to match /Checking for C compiler\.\.\. gcc/
|
expect(result.stdout).to match /Checking for C compiler\.\.\. gcc/
|
||||||
expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. g\+\+/
|
expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. g\+\+/
|
||||||
@@ -2244,6 +2360,8 @@ EOF
|
|||||||
expect(result.stdout).to match /Checking for D import 'std.stdio'\.\.\. found/
|
expect(result.stdout).to match /Checking for D import 'std.stdio'\.\.\. found/
|
||||||
expect(result.stdout).to match /Checking for library 'm'\.\.\. found/
|
expect(result.stdout).to match /Checking for library 'm'\.\.\. found/
|
||||||
expect(result.stdout).to match /Checking for program 'ls'\.\.\. .*ls/
|
expect(result.stdout).to match /Checking for program 'ls'\.\.\. .*ls/
|
||||||
|
expect(Dir.exist?("build")).to be_falsey
|
||||||
|
expect(Dir.exist?("bb/_configure")).to be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it "aggregates multiple set_define's" do
|
it "aggregates multiple set_define's" do
|
||||||
@@ -2306,7 +2424,6 @@ EOF
|
|||||||
expect(result.status).to eq 0
|
expect(result.status).to eq 0
|
||||||
expect(File.exists?("simple.o")).to be_falsey
|
expect(File.exists?("simple.o")).to be_falsey
|
||||||
expect(File.exists?("build")).to be_falsey
|
expect(File.exists?("build")).to be_falsey
|
||||||
expect(File.exists?(Rscons::Cache::CACHE_FILE)).to be_falsey
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2379,7 +2496,7 @@ EOF
|
|||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(result.stdout).to match %r{Compiling/Linking}
|
expect(result.stdout).to match %r{Compiling/Linking}
|
||||||
expect(File.exists?("test.exe")).to be_truthy
|
expect(File.exists?("test.exe")).to be_truthy
|
||||||
ld_library_path_prefix = (RUBY_PLATFORM =~ /mingw/ ? "" : "LD_LIBRARY_PATH=. ")
|
ld_library_path_prefix = (RUBY_PLATFORM =~ /mingw|msys/ ? "" : "LD_LIBRARY_PATH=. ")
|
||||||
expect(`#{ld_library_path_prefix}./test.exe`).to match /three/
|
expect(`#{ld_library_path_prefix}./test.exe`).to match /three/
|
||||||
|
|
||||||
result = run_rscons(rsconscript: "c_shared_library.rb")
|
result = run_rscons(rsconscript: "c_shared_library.rb")
|
||||||
@@ -2574,4 +2691,188 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "with subsidiary scripts" do
|
||||||
|
context "with a script specified" do
|
||||||
|
it "executes the subsidiary script from configure block" do
|
||||||
|
test_dir "subsidiary"
|
||||||
|
|
||||||
|
result = run_rscons(op: %W[configure])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
%r{Entering directory '.*/sub'},
|
||||||
|
%r{sub Rsconscript configure},
|
||||||
|
%r{Leaving directory '.*/sub'},
|
||||||
|
%r{Entering directory '.*/sub'},
|
||||||
|
%r{sub Rsconscript build},
|
||||||
|
%r{Leaving directory '.*/sub'},
|
||||||
|
%r{Entering directory '.*/sub'},
|
||||||
|
%r{sub Rsconscript2 configure},
|
||||||
|
%r{Leaving directory '.*/sub'},
|
||||||
|
%r{top configure},
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "executes the subsidiary script from build block" do
|
||||||
|
test_dir "subsidiary"
|
||||||
|
|
||||||
|
result = run_rscons(op: %W[configure])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
result = run_rscons(op: %W[build])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
%r{sub Rsconscript2 build},
|
||||||
|
%r{top build},
|
||||||
|
])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a directory specified" do
|
||||||
|
it "executes the subsidiary script from configure block" do
|
||||||
|
test_dir "subsidiary"
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "Rsconscript_dir", op: %W[configure])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
%r{Entering directory '.*/sub'},
|
||||||
|
%r{sub Rsconscript configure},
|
||||||
|
%r{Leaving directory '.*/sub'},
|
||||||
|
%r{Entering directory '.*/sub'},
|
||||||
|
%r{sub Rsconscript build},
|
||||||
|
%r{Leaving directory '.*/sub'},
|
||||||
|
%r{Entering directory '.*/sub'},
|
||||||
|
%r{sub Rsconscript2 configure},
|
||||||
|
%r{Leaving directory '.*/sub'},
|
||||||
|
%r{top configure},
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "executes the subsidiary script from build block" do
|
||||||
|
test_dir "subsidiary"
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "Rsconscript_dir", op: %W[configure])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
result = run_rscons(rsconscript: "Rsconscript_dir", op: %W[build])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
%r{sub Rsconscript2 build},
|
||||||
|
%r{top build},
|
||||||
|
])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a rscons binary in the subsidiary script directory" do
|
||||||
|
it "executes rscons from the subsidiary script directory" do
|
||||||
|
test_dir "subsidiary"
|
||||||
|
|
||||||
|
File.binwrite("sub/rscons", <<EOF)
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
puts "sub rscons"
|
||||||
|
EOF
|
||||||
|
FileUtils.chmod(0755, "sub/rscons")
|
||||||
|
result = run_rscons(op: %W[configure])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
%r{Entering directory '.*/sub'},
|
||||||
|
%r{sub rscons},
|
||||||
|
%r{Leaving directory '.*/sub'},
|
||||||
|
%r{Entering directory '.*/sub'},
|
||||||
|
%r{sub rscons},
|
||||||
|
%r{Leaving directory '.*/sub'},
|
||||||
|
%r{Entering directory '.*/sub'},
|
||||||
|
%r{sub rscons},
|
||||||
|
%r{Leaving directory '.*/sub'},
|
||||||
|
%r{top configure},
|
||||||
|
])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not print entering/leaving directory messages when the subsidiary script is in the same directory" do
|
||||||
|
test_dir "subsidiary"
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "Rsconscript_samedir", op: %W[configure])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
result = run_rscons(rsconscript: "Rsconscript_samedir", op: %W[build])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.stdout).to_not match(%{(Entering|Leaving) directory})
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
%r{second build},
|
||||||
|
%r{top build},
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "terminates execution when a subsidiary script fails" do
|
||||||
|
test_dir "subsidiary"
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "Rsconscript_fail", op: %W[configure])
|
||||||
|
expect(result.stderr).to_not eq ""
|
||||||
|
expect(result.status).to_not eq 0
|
||||||
|
expect(result.stdout).to_not match /top configure/
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not pass RSCONS_BUILD_DIR to subsidiary scripts" do
|
||||||
|
test_dir "subsidiary"
|
||||||
|
passenv["RSCONS_BUILD_DIR"] = "buildit"
|
||||||
|
result = run_rscons(op: %W[configure])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(Dir.exist?("build")).to be_falsey
|
||||||
|
expect(Dir.exist?("buildit")).to be_truthy
|
||||||
|
expect(Dir.exist?("sub/build")).to be_truthy
|
||||||
|
expect(Dir.exist?("sub/buildit")).to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "sh method" do
|
||||||
|
it "executes the command given" do
|
||||||
|
test_dir "sh"
|
||||||
|
result = run_rscons(rsconscript: "sh.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
"hi there",
|
||||||
|
"1 2",
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints the command when executing verbosely" do
|
||||||
|
test_dir "sh"
|
||||||
|
result = run_rscons(rsconscript: "sh.rb", rscons_args: %w[-v])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
%r{echo 'hi there'},
|
||||||
|
"hi there",
|
||||||
|
%r{echo 1 2},
|
||||||
|
"1 2",
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "terminates execution on failure" do
|
||||||
|
test_dir "sh"
|
||||||
|
result = run_rscons(rsconscript: "sh_fail.rb")
|
||||||
|
expect(result.stderr).to match /sh_fail\.rb:2:.*foobar42/
|
||||||
|
expect(result.status).to_not eq 0
|
||||||
|
expect(result.stdout).to_not match /continued/
|
||||||
|
end
|
||||||
|
|
||||||
|
it "continues execution on failure when :continue option is set" do
|
||||||
|
test_dir "sh"
|
||||||
|
result = run_rscons(rsconscript: "sh_fail_continue.rb")
|
||||||
|
expect(result.stderr).to match /sh_fail_continue\.rb:2:.*foobar42/
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
expect(result.stdout).to match /continued/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "FileUtils methods" do
|
||||||
|
it "defines FileUtils methods to be available in the build script" do
|
||||||
|
test_dir "typical"
|
||||||
|
result = run_rscons(rsconscript: "fileutils_methods.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
expect(Dir.exist?("foobar")).to be_truthy
|
||||||
|
expect(Dir.exist?("foo")).to be_falsey
|
||||||
|
expect(File.exist?("foobar/baz/b.txt")).to be_truthy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -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
|
||||||
|
|||||||
+3
-3
@@ -1,3 +1,6 @@
|
|||||||
|
if ENV["dist_specs"]
|
||||||
|
require_relative "../test/rscons"
|
||||||
|
else
|
||||||
require "simplecov"
|
require "simplecov"
|
||||||
|
|
||||||
SimpleCov.start do
|
SimpleCov.start do
|
||||||
@@ -18,8 +21,5 @@ SimpleCov.start do
|
|||||||
merge_timeout 3600
|
merge_timeout 3600
|
||||||
end
|
end
|
||||||
|
|
||||||
if ENV["dist_specs"]
|
|
||||||
require_relative "../test/rscons"
|
|
||||||
else
|
|
||||||
require "rscons"
|
require "rscons"
|
||||||
end
|
end
|
||||||
Reference in new issue
Block a user