Compare commits
86
Commits
v2.0.0beta1
...
v2.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
d08e2f6b5c | ||
|
|
90365dd197 | ||
|
|
8d05516c40 | ||
|
|
db49d86866 | ||
|
|
e667455c32 | ||
|
|
e62332aba6 | ||
|
|
397639849d | ||
|
|
96d5caf2e5 | ||
|
|
f4b10a30af | ||
|
|
cf52c3fc6f | ||
|
|
5378afb6f8 | ||
|
|
48d9273cc6 | ||
|
|
efea4f1181 | ||
|
|
b4fa6d965c | ||
|
|
ac56ad34f6 | ||
|
|
2fd533a32a | ||
|
|
c938ed71d1 | ||
|
|
ec60201a62 | ||
|
|
0cafb8c5b3 | ||
|
|
004810386b | ||
|
|
a15ee9daaf | ||
|
|
cd33405697 | ||
|
|
efa77066bf | ||
|
|
a1bb9d81fd | ||
|
|
0344f02cb1 | ||
|
|
d52bdaf046 | ||
|
|
ad7ccb771d | ||
|
|
044ee343ca | ||
|
|
eb54a2b64a | ||
|
|
2dd1ce9f1d | ||
|
|
1e157c79ec | ||
|
|
2385874f4a | ||
|
|
c5c42e6f4a | ||
|
|
9a627b2150 | ||
|
|
937c964c3e | ||
|
|
a2a1d08014 | ||
|
|
0ccf43cc96 | ||
|
|
d202e15a57 | ||
|
|
94f808b1fc | ||
|
|
51a9dd365f | ||
|
|
6e590b62a6 | ||
|
|
3aac190ad6 | ||
|
|
d6b9487e65 | ||
|
|
66d2700faa | ||
|
|
ba98af1424 | ||
|
|
cf4f80c9ae | ||
|
|
d74785d579 | ||
|
|
4fd822fb95 | ||
|
|
b39fd80d8c | ||
|
|
ef00c9f377 |
No files matched your search
@@ -1,3 +1,81 @@
|
|||||||
|
## v2.3.0
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
- #125 - Support subsidiary Rsconscript files
|
||||||
|
- #126 - Add PATH manipulation methods
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- #121 - env.depends() does not work with built-root-relative "^/" paths
|
||||||
|
- #130 - Document -f command line option
|
||||||
|
- #133 - Clarify failed command error message indicating to run -F
|
||||||
|
- #134 - Document CMD_STDOUT variable for Command builder
|
||||||
|
- #135 - Write dependency file to build directory when user invokes Object builder directly
|
||||||
|
- #141 - Document phony targets
|
||||||
|
|
||||||
|
## v2.2.0
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
- #120 - improve support for MSYS2
|
||||||
|
- #119 - add failure messages for failed configuration checks
|
||||||
|
- #118 - compiler checks should support cross-compilers and freestanding compilers
|
||||||
|
|
||||||
|
## v2.1.0
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
- #117 - ruby 2.7 compatibility
|
||||||
|
|
||||||
|
## v2.0.2
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- #113 - distinguish object files built from multiple sources with the same base name but different extensions
|
||||||
|
|
||||||
|
## v2.0.1
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- #112 - Install builder cannot replace a currently executing binary on Linux
|
||||||
|
|
||||||
|
## v2.0.0
|
||||||
|
|
||||||
|
- convert rscons from a Ruby gem to a standalone script
|
||||||
|
- compress rscons distributable script
|
||||||
|
- add configure operation to detect compilers, check for headers/libraries, etc... (invoked automatically if needed)
|
||||||
|
- Environments store builder classes instead of instances of builder classes
|
||||||
|
- use a separate Builder instance for each build operation
|
||||||
|
- load Rsconscript from Rsconscript/Rsconscript.rb instead of Rsconsfile
|
||||||
|
- drop support for builder run methods using the old 5 parameter signature
|
||||||
|
- remove Environment#build_dir
|
||||||
|
- set Environment build root in configure step
|
||||||
|
- remove Builder#finalize (now #run called repeatedly until builder completes)
|
||||||
|
- remove Builder#setup
|
||||||
|
- remove Builder#features and Builder#produces?
|
||||||
|
- add functionality to allow builders to wait on Ruby threads or other builders
|
||||||
|
- add install/uninstall/distclean command-line operations
|
||||||
|
- preserve makefile dependency files under build directory
|
||||||
|
- remove a few deprecated methods
|
||||||
|
- pass a Builder instance to build hooks instead of a build operation Hash
|
||||||
|
- support a basic markup syntax in builder run messages to colorize target/source files
|
||||||
|
- hide (but store) failed compilation command by default so the user doesn't have to scroll back as much to see compiler output
|
||||||
|
- refactor to remove some redundancy among built-in builders
|
||||||
|
- track object file source language (correctly determine linker when only passed object files previously built by particular toolchains)
|
||||||
|
- add barriers
|
||||||
|
- add InstallDirectory builder
|
||||||
|
- change Install builder to copy files on 'install' operation
|
||||||
|
- add "prefix" construction variable based on configured installation prefix
|
||||||
|
- allow passing builder objects as sources to build targets
|
||||||
|
- differentiate 'build' targets from 'install' targets in cache contents
|
||||||
|
- add verbose mode
|
||||||
|
- show build progress as a percentage in builder output messages
|
||||||
|
- various performance improvements
|
||||||
|
- wrote a new user guide
|
||||||
|
- added new website ([https://holtrop.github.io/rscons/](https://holtrop.github.io/rscons/))
|
||||||
|
- added new logo
|
||||||
|
|
||||||
## v1.17.0
|
## v1.17.0
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
# Rscons
|
# Rscons
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Rscons (https://github.com/holtrop/rscons) is an open-source build system
|
Rscons (https://github.com/holtrop/rscons) is an open-source build system
|
||||||
for developers.
|
for developers.
|
||||||
|
|
||||||
Rscons is written in Ruby, and is inspired by [SCons](https://scons.org/) and [waf](https://waf.io/).
|
Rscons is written in Ruby, and is inspired by [SCons](https://scons.org/) and [waf](https://waf.io/).
|
||||||
|
|
||||||
|
See [https://holtrop.github.io/rscons/index.html](https://holtrop.github.io/rscons/index.html) for User Guide and Installation instructions.
|
||||||
+23
-8
@@ -6,24 +6,27 @@ rescue Bundler::BundlerError => e
|
|||||||
end
|
end
|
||||||
|
|
||||||
require "rspec/core/rake_task"
|
require "rspec/core/rake_task"
|
||||||
require "yard"
|
|
||||||
require "rake/clean"
|
require "rake/clean"
|
||||||
require "fileutils"
|
require "fileutils"
|
||||||
|
|
||||||
CLEAN.include %w[build_test_run .yardoc yard coverage test]
|
CLEAN.include %w[build_test_run .yardoc yard coverage test]
|
||||||
CLOBBER.include %w[dist pkg]
|
CLOBBER.include %w[dist gen large_project pkg]
|
||||||
|
|
||||||
task :build_dist do
|
task :build_dist do
|
||||||
sh "ruby rb/build_dist.rb"
|
sh "ruby rb/build_dist.rb"
|
||||||
end
|
end
|
||||||
|
|
||||||
RSpec::Core::RakeTask.new(:spec, :example_string) do |task, args|
|
RSpec::Core::RakeTask.new(:spec, :example_string) do |task, args|
|
||||||
|
ENV["specs"] = "1"
|
||||||
if args.example_string
|
if args.example_string
|
||||||
ENV["partial_specs"] = "1"
|
ENV["partial_specs"] = "1"
|
||||||
task.rspec_opts = %W[-e "#{args.example_string}" -f documentation]
|
task.rspec_opts = %W[-e "#{args.example_string}" -f documentation]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
task :spec => :build_dist
|
task :spec => :build_dist
|
||||||
|
task :spec do
|
||||||
|
ENV.delete("specs")
|
||||||
|
end
|
||||||
|
|
||||||
# dspec task is useful to test the distributable release script, but is not
|
# dspec task is useful to test the distributable release script, but is not
|
||||||
# useful for coverage information.
|
# useful for coverage information.
|
||||||
@@ -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,8 +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 => [
|
||||||
|
:build_dist,
|
||||||
|
:spec,
|
||||||
|
:dspec,
|
||||||
|
:yard,
|
||||||
|
:user_guide,
|
||||||
|
]
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
configure do
|
||||||
|
check_c_header "string.h", check_cpppath: ["./usr1"]
|
||||||
|
check_c_header "frobulous.h", check_cpppath: ["./usr2"]
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.Object("test.o", "test.c")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
configure do
|
configure do
|
||||||
check_c_header "not___found.h", fail: false, set_define: "HAVE_NOT___FOUND_H"
|
check_c_header "not___found.h", set_define: "HAVE_NOT___FOUND_H"
|
||||||
end
|
end
|
||||||
|
|
||||||
build do
|
build do
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
configure do
|
||||||
|
check_cxx_header "string.h", check_cpppath: ["./usr1"]
|
||||||
|
check_cxx_header "frobulous.h", check_cpppath: ["./usr2"]
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.Object("test.o", "test.cc")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
configure do
|
||||||
|
check_d_compiler
|
||||||
|
check_d_import "std.stdio", check_d_import_path: ["./usr1"]
|
||||||
|
check_d_import "frobulous", check_d_import_path: ["./usr2"]
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.Object("test.o", "test.d")
|
||||||
|
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 @@
|
|||||||
|
build do
|
||||||
|
Environment.new(echo: :command) do |env|
|
||||||
|
env.Library("usr2/libfrobulous.a", "two.c")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
configure do
|
||||||
|
check_lib "m", check_libpath: ["./usr1"]
|
||||||
|
check_lib "frobulous", check_libpath: ["./usr2"]
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
Environment.new(echo: :command) do |env|
|
||||||
|
env.Program("simple.exe", "simple.c")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
configure do
|
||||||
|
custom_check("Checking 'grep' version") do |op|
|
||||||
|
stdout, stderr, status = op.log_and_test_command(%w[grep --version])
|
||||||
|
should_fail = true
|
||||||
|
if status != 0
|
||||||
|
fail_message = "error executing grep"
|
||||||
|
elsif stdout =~ /^grep \(GNU grep\) 1\./
|
||||||
|
fail_message = "too old!"
|
||||||
|
status = 1
|
||||||
|
elsif stdout =~ /^grep \(GNU grep\) 2\./
|
||||||
|
fail_message = "we'll work with it but you should upgrade"
|
||||||
|
status = 1
|
||||||
|
should_fail = false
|
||||||
|
op.store_merge("CPPDEFINES" => "GREP_WORKAROUND")
|
||||||
|
else
|
||||||
|
op.store_append("CPPDEFINES" => "GREP_FULL")
|
||||||
|
end
|
||||||
|
op.complete(status, success_message: "good!", fail_message: fail_message, fail: should_fail)
|
||||||
|
end
|
||||||
|
custom_check("Checking sed -E flag") do |op|
|
||||||
|
stdout, stderr, status = op.log_and_test_command(%w[sed -E -e s/ab+/rep/], stdin: "abbbc")
|
||||||
|
op.complete(stdout =~ /repc/ ? 0 : 1, success_message: "good", fail_message: "fail")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
puts env["CPPDEFINES"]
|
||||||
|
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
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
int two(void)
|
||||||
|
{
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
@@ -6,7 +6,8 @@ build do
|
|||||||
"CMD_DESC" => "Generating")
|
"CMD_DESC" => "Generating")
|
||||||
env["build_root"] = env.build_root
|
env["build_root"] = env.build_root
|
||||||
env["inc_c"] = "inc.c"
|
env["inc_c"] = "inc.c"
|
||||||
env.build_after("${build_root}/program.o", "${inc_c}")
|
env.Object("program.o", "program.c")
|
||||||
env.Program("program.exe", ["program.c", "inc.c"])
|
env.build_after("program.o", "${inc_c}")
|
||||||
|
env.Program("program.exe", ["program.o", "inc.c"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -4,8 +4,9 @@ build do
|
|||||||
env["inc_h"] = "inc.h"
|
env["inc_h"] = "inc.h"
|
||||||
|
|
||||||
env.Copy("copy_inc.h", "${inc_h}")
|
env.Copy("copy_inc.h", "${inc_h}")
|
||||||
env.depends("${build_root}/program.o", "${inc_h}")
|
env.depends("program.o", "${inc_h}")
|
||||||
env.Program("program.exe", ["program.c", "inc.c"])
|
env.Object("program.o", "program.c")
|
||||||
|
env.Program("program.exe", ["program.o", "inc.c"])
|
||||||
|
|
||||||
inc_c = env.Command("inc.c",
|
inc_c = env.Command("inc.c",
|
||||||
[],
|
[],
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ build do
|
|||||||
env["inc_h"] = "inc.h"
|
env["inc_h"] = "inc.h"
|
||||||
|
|
||||||
env.Copy("copy_inc.h", "${inc_h}")
|
env.Copy("copy_inc.h", "${inc_h}")
|
||||||
env.depends("${build_root}/program.o", "${inc_h}")
|
env.depends("program.o", "${inc_h}")
|
||||||
env.Program("program.exe", ["program.c", "inc.c"])
|
env.Object("program.o", "program.c")
|
||||||
|
env.Program("program.exe", ["program.o", "inc.c"])
|
||||||
|
|
||||||
env.Command("inc.c",
|
env.Command("inc.c",
|
||||||
[],
|
[],
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
configure do
|
||||||
|
check_d_compiler "gdc"
|
||||||
|
end
|
||||||
|
|
||||||
build do
|
build do
|
||||||
Environment.new(echo: :command) do |env|
|
Environment.new(echo: :command) do |env|
|
||||||
env.Program("hello-d.exe", glob("*.d"))
|
env.Program("hello-d.exe", glob("*.d"))
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
configure do
|
||||||
|
check_d_compiler "ldc2"
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
Environment.new(echo: :command) do |env|
|
||||||
|
env.Program("hello-d.exe", glob("*.d"))
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -4,6 +4,7 @@ build do
|
|||||||
require 'yaml'
|
require 'yaml'
|
||||||
env.add_builder(:JsonToYaml) do |params|
|
env.add_builder(:JsonToYaml) do |params|
|
||||||
unless @cache.up_to_date?(@target, :JsonToYaml, @sources, @env)
|
unless @cache.up_to_date?(@target, :JsonToYaml, @sources, @env)
|
||||||
|
print_run_message("JsonToYaml #{@target}", nil)
|
||||||
@cache.mkdir_p(File.dirname(@target))
|
@cache.mkdir_p(File.dirname(@target))
|
||||||
File.open(@target, 'w') do |f|
|
File.open(@target, 'w') do |f|
|
||||||
f.write(YAML.dump(JSON.load(IO.read(@sources.first))))
|
f.write(YAML.dump(JSON.load(IO.read(@sources.first))))
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.Program("foo.exe", glob("*.cc", "*.c"))
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void foo(void)
|
||||||
|
{
|
||||||
|
printf("foo\n");
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void foo(void);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
foo();
|
||||||
|
std::cout << "main" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
build do
|
build do
|
||||||
Environment.new do |env|
|
Environment.new do |env|
|
||||||
env["LIBS"] += ["c"]
|
env["LIBS"] += ["m"]
|
||||||
env.Program('simple.exe', Dir['*.c'])
|
env.Program('simple.exe', Dir['*.c'])
|
||||||
end
|
end
|
||||||
end
|
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,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
|
||||||
@@ -2,9 +2,9 @@ build do
|
|||||||
Environment.new(echo: :command) do |env|
|
Environment.new(echo: :command) do |env|
|
||||||
env.append('CPPPATH' => glob('src/**/*/'))
|
env.append('CPPPATH' => glob('src/**/*/'))
|
||||||
env.add_build_hook do |builder|
|
env.add_build_hook do |builder|
|
||||||
if File.basename(builder.target) == "one.o"
|
if File.basename(builder.sources.first) == "one.c"
|
||||||
builder.vars["CFLAGS"] << "-O1"
|
builder.vars["CFLAGS"] << "-O1"
|
||||||
elsif File.basename(builder.target) == "two.o"
|
elsif File.basename(builder.sources.first) == "two.c"
|
||||||
builder.vars["CFLAGS"] << "-O2"
|
builder.vars["CFLAGS"] << "-O2"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+324
-27
@@ -8,7 +8,7 @@ It supports the following features:
|
|||||||
* built-in builders for several common operations
|
* built-in builders for several common operations
|
||||||
* out-of-the-box support for C, C++, and D languages
|
* out-of-the-box support for C, C++, and D languages
|
||||||
* extensibility for other languages or custom builders
|
* extensibility for other languages or custom builders
|
||||||
* compatible with Windows, Linux, and OS X
|
* compatible with Windows, Linux, OS X, and FreeBSD
|
||||||
* colorized output with build progress
|
* colorized output with build progress
|
||||||
* build hooks
|
* build hooks
|
||||||
|
|
||||||
@@ -24,6 +24,15 @@ custom build operations as well.
|
|||||||
|
|
||||||
Rscons is written in Ruby, and is inspired by [SCons](https://scons.org/) and [waf](https://waf.io/).
|
Rscons is written in Ruby, and is inspired by [SCons](https://scons.org/) and [waf](https://waf.io/).
|
||||||
|
|
||||||
|
${remove}
|
||||||
|
WARNING: This user guide is meant to be preprocessed and rendered by a custom
|
||||||
|
script.
|
||||||
|
The markdown source file is not intended to be viewed directly and will not
|
||||||
|
include all intended content.
|
||||||
|
Visit [https://holtrop.github.io/rscons/index.html](https://holtrop.github.io/rscons/index.html)
|
||||||
|
to view the properly rendered version.
|
||||||
|
${/remove}
|
||||||
|
|
||||||
## Design Principles
|
## Design Principles
|
||||||
|
|
||||||
### Build Correctness
|
### Build Correctness
|
||||||
@@ -89,7 +98,8 @@ The only dependency required to run Rscons is to have a Ruby interpreter
|
|||||||
installed.
|
installed.
|
||||||
The latest release can be downloaded from [https://github.com/holtrop/rscons/releases](https://github.com/holtrop/rscons/releases).
|
The latest release can be downloaded from [https://github.com/holtrop/rscons/releases](https://github.com/holtrop/rscons/releases).
|
||||||
Simply copy the `rscons` executable script into the desired location within
|
Simply copy the `rscons` executable script into the desired location within
|
||||||
the project to be built (typically the root of the repository).
|
the project to be built (typically the root of the repository) and mark it
|
||||||
|
executable.
|
||||||
|
|
||||||
## Version Control Setup
|
## Version Control Setup
|
||||||
|
|
||||||
@@ -131,6 +141,7 @@ Such configuration checks can include:
|
|||||||
* verifying presence of a D import
|
* verifying presence of a D import
|
||||||
* verifying presence of a library
|
* verifying presence of a library
|
||||||
* verifying presence of an executable
|
* verifying presence of an executable
|
||||||
|
* any custom user-supplied configuration check
|
||||||
|
|
||||||
##> Build Operation
|
##> Build Operation
|
||||||
|
|
||||||
@@ -140,6 +151,17 @@ been performed, a `configure` operation will be automatically invoked.
|
|||||||
The `build` operation will execute all builders registered to produce build
|
The `build` operation will execute all builders registered to produce build
|
||||||
targets.
|
targets.
|
||||||
|
|
||||||
|
If a `build` operation fails (e.g. due to a compilation failure), Rscons will
|
||||||
|
log the failed commands.
|
||||||
|
By default Rscons does not print the failed commands to the console so that it
|
||||||
|
is easier for the user to focus on the actual compiler failure messages rather
|
||||||
|
than the compilation command itself.
|
||||||
|
However, if the user wishes to see the compilation commands, rscons can be
|
||||||
|
invoked with the `-v` command-line option to show all complilation commands
|
||||||
|
while building, or, alternatively, following a compilation failure, the user
|
||||||
|
can invoke rscons with the -F option which will not rebuild but will show the
|
||||||
|
failed command log from the previous build operation.
|
||||||
|
|
||||||
##> Clean Operation
|
##> Clean Operation
|
||||||
|
|
||||||
A `clean` operation will remove all built target files.
|
A `clean` operation will remove all built target files.
|
||||||
@@ -211,6 +233,7 @@ working compiler:
|
|||||||
|
|
||||||
Each of these methods can take an optional list of compilers to check for.
|
Each of these methods can take an optional list of compilers to check for.
|
||||||
If such a list is supplied, the compilers are tested in the order listed.
|
If such a list is supplied, the compilers are tested in the order listed.
|
||||||
|
The first compiler option found which passes a compilation test is used.
|
||||||
|
|
||||||
Here are example calls which also show the default compiler list for each
|
Here are example calls which also show the default compiler list for each
|
||||||
supported language:
|
supported language:
|
||||||
@@ -223,6 +246,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:
|
||||||
@@ -237,7 +269,7 @@ Example calls:
|
|||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
configure do
|
configure do
|
||||||
check_c_header "getopt.h", fail: false, set_define: "HAVE_GETOPT_H"
|
check_c_header "getopt.h", set_define: "HAVE_GETOPT_H"
|
||||||
check_c_header "FreeType2.h"
|
check_c_header "FreeType2.h"
|
||||||
check_cxx_header "memory"
|
check_cxx_header "memory"
|
||||||
end
|
end
|
||||||
@@ -245,15 +277,9 @@ end
|
|||||||
|
|
||||||
#### Options
|
#### Options
|
||||||
|
|
||||||
##### `:fail`
|
##### `:check_cpppath`
|
||||||
|
|
||||||
If the `:fail` option is set to `false`, then the absence of the header file
|
Optionally specifies an array of paths to look for the header file in.
|
||||||
will not result in the configure option failing.
|
|
||||||
|
|
||||||
##### `: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
|
||||||
|
|
||||||
@@ -270,6 +296,12 @@ configure do
|
|||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
##### `:check_d_import_path`
|
||||||
|
|
||||||
|
Optionally specifies an array of paths to look for the module in.
|
||||||
|
|
||||||
###> Checking for a Library
|
###> Checking for a Library
|
||||||
|
|
||||||
The `check_lib` method can be used to check for the presence of a library.
|
The `check_lib` method can be used to check for the presence of a library.
|
||||||
@@ -288,15 +320,15 @@ end
|
|||||||
|
|
||||||
#### Options
|
#### Options
|
||||||
|
|
||||||
##### `:fail`
|
##### `:check_libpath`
|
||||||
|
|
||||||
If the `:fail` option is set to `false`, then the absence of the library
|
Optionally specifies an array of paths to look for the library in.
|
||||||
will not result in the configure option failing.
|
|
||||||
|
|
||||||
##### `:set_define`
|
##### `:use`
|
||||||
|
|
||||||
If set, a build define of the specified String will be added to the
|
If not set, the library will be used by default in all `Environment` objects.
|
||||||
`CPPDEFINES` construction variable array if the requested library is found.
|
If set, the library will only be used in `Environment` objects that have a
|
||||||
|
matching `:use` flag set.
|
||||||
|
|
||||||
###> Checking for a Program
|
###> Checking for a Program
|
||||||
|
|
||||||
@@ -340,12 +372,100 @@ 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`
|
##### `:use`
|
||||||
|
|
||||||
|
If not set, the library will be used by default in all `Environment` objects.
|
||||||
|
If set, the library will only be used in `Environment` objects that have a
|
||||||
|
matching `:use` flag set.
|
||||||
|
|
||||||
|
###> Custom Configuration Checks
|
||||||
|
|
||||||
|
The `Rsconscript` author can add custom configuration checks to be performed
|
||||||
|
during the rscons `configure` operation.
|
||||||
|
|
||||||
|
Here is an example from `build_tests/configure/custom_config_check.rb` showing
|
||||||
|
a custom configuration check:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
${include build_tests/configure/custom_config_check.rb}
|
||||||
|
```
|
||||||
|
|
||||||
|
A custom configuration check is created by calling the `custom_check` method
|
||||||
|
and passing a block.
|
||||||
|
The contents of the block should perform the custom configuration checking
|
||||||
|
logic.
|
||||||
|
This logic can include executing a test command or other arbitrary operations.
|
||||||
|
An argument `op` is passed to the block.
|
||||||
|
This object is an instance of the [`ConfigureOp` class](../yard/Rscons/ConfigureOp.html)
|
||||||
|
class and provides several methods that can be used to aid with the custom
|
||||||
|
configuration check.
|
||||||
|
The [`log_and_test_command`](../yard/Rscons/ConfigureOp.html#log_and_test_command-instance_method)
|
||||||
|
method can be used to execute a test command and retrieve its results.
|
||||||
|
The command and its output are also logged to the config.log file.
|
||||||
|
The [`store_merge`](../yard/Rscons/ConfigureOp.html#store_merge-instance_method),
|
||||||
|
[`store_append`](../yard/Rscons/ConfigureOp.html#store_append-instance_method),
|
||||||
|
and [`store_parse`](../yard/Rscons/ConfigureOp.html#store_parse-instance_method)
|
||||||
|
methods can be used to store construction variables for Environments created
|
||||||
|
during the `build` operation.
|
||||||
|
Finally, the [`complete`](../yard/Rscons/ConfigureOp.html#complete-instance_method)
|
||||||
|
method can be used to complete the configuration check and indicate a success
|
||||||
|
or failure.
|
||||||
|
|
||||||
|
While performing a custom configuration check, it can sometimes be useful to
|
||||||
|
be able to construct an Environment to use the set of default construction
|
||||||
|
variables as defined so far in the configuration block, for example to expand
|
||||||
|
construction variables to build a test command.
|
||||||
|
The normal `Environment` class cannot be used within the `configure` block,
|
||||||
|
however the [`BasicEnvironment`](../yard/Rscons/BasicEnvironment.html) class
|
||||||
|
can be used for such a purpose.
|
||||||
|
|
||||||
|
For example, to expand the current `${CCCMD}` value:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
configure do
|
||||||
|
custom_check("Checking something to do with CCCMD") do
|
||||||
|
command = BasicEnvironment.new.expand_varref("${CCCMD}")
|
||||||
|
# ...
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
###> Global Configuration Check Options
|
||||||
|
|
||||||
|
#### `:fail`
|
||||||
|
|
||||||
If the `:fail` option is set to `false`, then the absence of the package or
|
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.
|
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`
|
#### `: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
|
If set, a build define of the specified String will be added to the
|
||||||
`CPPDEFINES` construction variable array if the requested package is found.
|
`CPPDEFINES` construction variable array if the requested package is found.
|
||||||
@@ -399,7 +519,8 @@ files.
|
|||||||
|
|
||||||
###> Specifying Source Files: The glob Method
|
###> Specifying Source Files: The glob Method
|
||||||
|
|
||||||
The `glob` method can be used to find files matching the patterns specified.
|
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.
|
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:
|
Example use:
|
||||||
@@ -491,14 +612,26 @@ There are several default builders that are built-in to Rscons:
|
|||||||
```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
|
||||||
@@ -622,6 +755,24 @@ A platform-dependent program suffix will be appended to the target name if one
|
|||||||
is not specified.
|
is not specified.
|
||||||
This can be controlled with the `PROGSUFFIX` construction variable.
|
This can be controlled with the `PROGSUFFIX` construction variable.
|
||||||
|
|
||||||
|
##### Direct Mode
|
||||||
|
|
||||||
|
The Program builder supports a "direct" mode which is activated by specifying
|
||||||
|
the `:direct` option.
|
||||||
|
In the direct mode, all source files are passed directly to the compiler
|
||||||
|
together and compiled and linked in one step, rather than being individually
|
||||||
|
compiled to separate object files first.
|
||||||
|
This mode allows taking advantage of any multi-file compilation capabilities
|
||||||
|
of the compiler.
|
||||||
|
However, it also requires recompiling all source files when any one of them
|
||||||
|
has changed.
|
||||||
|
|
||||||
|
Example use:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.Program("myprog", Rscons.glob("src/**/*.c"), direct: true)
|
||||||
|
```
|
||||||
|
|
||||||
####> The SharedLibrary Builder
|
####> The SharedLibrary Builder
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
@@ -638,6 +789,24 @@ they are not specified by the user.
|
|||||||
These values can be controlled by overriding the `SHLIBPREFIX` and
|
These values can be controlled by overriding the `SHLIBPREFIX` and
|
||||||
`SHLIBSUFFIX` construction variables.
|
`SHLIBSUFFIX` construction variables.
|
||||||
|
|
||||||
|
##### Direct Mode
|
||||||
|
|
||||||
|
The SharedLibrary builder supports a "direct" mode which is activated by
|
||||||
|
specifying the `:direct` option.
|
||||||
|
In the direct mode, all source files are passed directly to the compiler
|
||||||
|
together and compiled and linked in one step, rather than being individually
|
||||||
|
compiled to separate object files first.
|
||||||
|
This mode allows taking advantage of any multi-file compilation capabilities
|
||||||
|
of the compiler.
|
||||||
|
However, it also requires recompiling all source files when any one of them
|
||||||
|
has changed.
|
||||||
|
|
||||||
|
Example use:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.SharedLibrary("mydll", Rscons.glob("src/**/*.c"), direct: true)
|
||||||
|
```
|
||||||
|
|
||||||
####> The SharedObject Builder
|
####> The SharedObject Builder
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
@@ -652,6 +821,22 @@ 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.
|
||||||
|
|
||||||
|
###> 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
|
||||||
@@ -703,6 +888,82 @@ Post-build hooks are only invoked if the build operation was a success.
|
|||||||
|
|
||||||
Build hooks and post-build hooks can register new build targets.
|
Build hooks and post-build hooks can register new build targets.
|
||||||
|
|
||||||
|
###> Barriers
|
||||||
|
|
||||||
|
Normally Rscons will parallelize all builders.
|
||||||
|
A barrier can be used to separate sets of build targets.
|
||||||
|
All build targets registered before the barrier is created will be built before
|
||||||
|
Rscons will schedule any build targets after the barrier.
|
||||||
|
In other words, build targets are not parallelized across a barrier.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.barrier
|
||||||
|
```
|
||||||
|
|
||||||
|
##> Global Build Script Functionality
|
||||||
|
|
||||||
|
###> Using Subsidiary Build Scripts
|
||||||
|
|
||||||
|
The `rscons` 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.
|
||||||
|
|
||||||
|
###> PATH Management
|
||||||
|
|
||||||
|
`rscons` provides methods for management of the `PATH` environment variable.
|
||||||
|
|
||||||
|
The `path_append` and `path_prepend` 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` method sets the `PATH` environment variable to the given
|
||||||
|
Array or String.
|
||||||
|
The `path_components` method returns an Array of the components in the `PATH`
|
||||||
|
environment variable.
|
||||||
|
|
||||||
##> Extending Rscons
|
##> Extending Rscons
|
||||||
|
|
||||||
### Adding New Languages
|
### Adding New Languages
|
||||||
@@ -869,7 +1130,7 @@ Here is our Custom builder example extended to print its status:
|
|||||||
```ruby
|
```ruby
|
||||||
class Rscons::Builders::Custom < Rscons::Builder
|
class Rscons::Builders::Custom < Rscons::Builder
|
||||||
def run(options)
|
def run(options)
|
||||||
print_run_message("Creating <target>#{@target}<reset> from Custom builder")
|
print_run_message("Creating <target>#{@target}<reset> from Custom builder", nil)
|
||||||
File.open(@target, "w") do |fh|
|
File.open(@target, "w") do |fh|
|
||||||
fh.write("Target file created.")
|
fh.write("Target file created.")
|
||||||
end
|
end
|
||||||
@@ -894,7 +1155,7 @@ Here is a Custom builder which combines its source files similar to what the
|
|||||||
class Rscons::Builders::Custom < Rscons::Builder
|
class Rscons::Builders::Custom < Rscons::Builder
|
||||||
def run(options)
|
def run(options)
|
||||||
unless @cache.up_to_date?(@target, nil, @sources, @env)
|
unless @cache.up_to_date?(@target, nil, @sources, @env)
|
||||||
print_run_message("Combining <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>")
|
print_run_message("Combining <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", nil)
|
||||||
File.open(@target, "wb") do |fh|
|
File.open(@target, "wb") do |fh|
|
||||||
@sources.each do |source|
|
@sources.each do |source|
|
||||||
fh.write(File.read(source, mode: "rb"))
|
fh.write(File.read(source, mode: "rb"))
|
||||||
@@ -952,9 +1213,9 @@ the `Rscons::Command` class and then `wait_for` the Command object.
|
|||||||
However, this is a common enough case that Rscons provides a few
|
However, this is a common enough case that Rscons provides a few
|
||||||
convenience methods to handle this:
|
convenience methods to handle this:
|
||||||
|
|
||||||
* `Rscons::Builder#register_command`
|
* [`Rscons::Builder#register_command`](../yard/Rscons/Builder.html#register_command-instance_method)
|
||||||
* `Rscons::Builder#standard_command`
|
* [`Rscons::Builder#standard_command`](../yard/Rscons/Builder.html#standard_command-instance_method)
|
||||||
* `Rscons::Builder#finalize_command`
|
* [`Rscons::Builder#finalize_command`](../yard/Rscons/Builder.html#finalize_command-instance_method)
|
||||||
|
|
||||||
The `register_command` helper method can be used to create a Command object
|
The `register_command` helper method can be used to create a Command object
|
||||||
and wait for it to complete.
|
and wait for it to complete.
|
||||||
@@ -1104,6 +1365,42 @@ build do
|
|||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##> ./configure && make
|
||||||
|
|
||||||
|
You can make your Rscons-based project more familiar to users of
|
||||||
|
autoconf-generated projects by creating a `configure` script and a `Makefile`
|
||||||
|
for the user.
|
||||||
|
Such users may be used to executing:
|
||||||
|
|
||||||
|
```
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
to build a project.
|
||||||
|
To do this, create a `configure` script with contents similar to the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
#!/bin/sh
|
||||||
|
exec "$(dirname "$0")"/rscons configure "$@"
|
||||||
|
```
|
||||||
|
|
||||||
|
and make it executable with `chmod +x configure`.
|
||||||
|
|
||||||
|
If you want your users to be able to build/clean a project with `make` but
|
||||||
|
still make use of Rscons under the hood, you can create a `Makefile` with
|
||||||
|
contents something like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
.PHONY: all
|
||||||
|
all:
|
||||||
|
./rscons build
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
./rscons clean
|
||||||
|
```
|
||||||
|
|
||||||
##> YARD API Documentation
|
##> YARD API Documentation
|
||||||
|
|
||||||
See [here](../yard/index.html) for Rscons YARD API Documentation.
|
See [here](../yard/index.html) for Rscons YARD API Documentation.
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
+4
-14
@@ -35,8 +35,8 @@ module Rscons
|
|||||||
:SharedObject,
|
:SharedObject,
|
||||||
]
|
]
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
@@ -64,16 +64,6 @@ module Rscons
|
|||||||
target.is_a?(Symbol)
|
target.is_a?(Symbol)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return a new path by changing the suffix in path to suffix.
|
|
||||||
#
|
|
||||||
# @param path [String] The path to alter.
|
|
||||||
# @param suffix [String] The new filename suffix, e.g. ".exe".
|
|
||||||
#
|
|
||||||
# @return [String] New path.
|
|
||||||
def set_suffix(path, suffix)
|
|
||||||
path.sub(/\.[^.]*$/, "") + suffix
|
|
||||||
end
|
|
||||||
|
|
||||||
# Return the system shell and arguments for executing a shell command.
|
# Return the system shell and arguments for executing a shell command.
|
||||||
#
|
#
|
||||||
# @return [Array<String>] The shell and flag.
|
# @return [Array<String>] The shell and flag.
|
||||||
@@ -91,7 +81,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"]
|
||||||
@@ -112,7 +102,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"
|
||||||
|
|||||||
+2
-1
@@ -3,6 +3,7 @@ module Rscons
|
|||||||
module Ansi
|
module Ansi
|
||||||
class << self
|
class << self
|
||||||
|
|
||||||
|
# ANSI terminal reset sequence.
|
||||||
RESET = "\e[0m"
|
RESET = "\e[0m"
|
||||||
|
|
||||||
# Write a message to an IO with ANSI escape codes.
|
# Write a message to an IO with ANSI escape codes.
|
||||||
@@ -83,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?
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ module Rscons
|
|||||||
end
|
end
|
||||||
if rv == 0
|
if rv == 0
|
||||||
build(operation_options)
|
build(operation_options)
|
||||||
|
else
|
||||||
|
rv
|
||||||
end
|
end
|
||||||
when "clean"
|
when "clean"
|
||||||
clean
|
clean
|
||||||
@@ -134,8 +136,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
|
||||||
@@ -191,7 +193,11 @@ 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")
|
||||||
rv = 1
|
rv = 1
|
||||||
end
|
end
|
||||||
co.close(rv == 0)
|
co.close(rv == 0)
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ module Rscons
|
|||||||
|
|
||||||
# Create a BasicEnvironment object.
|
# Create a BasicEnvironment object.
|
||||||
#
|
#
|
||||||
# @api private
|
|
||||||
#
|
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# Construction options.
|
# Construction options.
|
||||||
|
# @option options [String, Array<String>] :use
|
||||||
|
# Use flag(s). If specified, any configuration flags which were saved
|
||||||
|
# with a corresponding `:use` value will be applied to this Environment.
|
||||||
def initialize(options = {})
|
def initialize(options = {})
|
||||||
@varset = VarSet.new(Rscons::DEFAULT_CONSTRUCTION_VARIABLES)
|
@varset = VarSet.new(Rscons::DEFAULT_CONSTRUCTION_VARIABLES)
|
||||||
load_configuration_data!(options)
|
load_configuration_data!(options)
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ module Rscons
|
|||||||
printed_message = true
|
printed_message = true
|
||||||
end
|
end
|
||||||
@cache.mkdir_p(File.dirname(dest), install: @install_builder)
|
@cache.mkdir_p(File.dirname(dest), install: @install_builder)
|
||||||
|
FileUtils.rm_f(dest)
|
||||||
FileUtils.cp(src, dest, :preserve => true)
|
FileUtils.cp(src, dest, :preserve => true)
|
||||||
end
|
end
|
||||||
@cache.register_build(dest, :Copy, [src], @env, install: @install_builder)
|
@cache.register_build(dest, :Copy, [src], @env, install: @install_builder)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ module Rscons
|
|||||||
def finalize_command_with_depfile
|
def finalize_command_with_depfile
|
||||||
deps = @sources
|
deps = @sources
|
||||||
if File.exists?(@vars["_DEPFILE"])
|
if File.exists?(@vars["_DEPFILE"])
|
||||||
deps += Util.parse_makefile_deps(@vars["_DEPFILE"])
|
deps += Util.parse_dependency_file(@vars["_DEPFILE"])
|
||||||
end
|
end
|
||||||
@cache.register_build(@target, @command, deps.uniq, @env)
|
@cache.register_build(@target, @command, deps.uniq, @env)
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ module Rscons
|
|||||||
|
|
||||||
module Builders
|
module Builders
|
||||||
module Mixins
|
module Mixins
|
||||||
|
# Mixin for builders needing to build object files.
|
||||||
module Object
|
module Object
|
||||||
|
|
||||||
include Depfile
|
include Depfile
|
||||||
@@ -74,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
|
||||||
Rscons.set_suffix(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)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ module Rscons
|
|||||||
@vars["_PREPROCESS_DEPGEN"] = depgen
|
@vars["_PREPROCESS_DEPGEN"] = depgen
|
||||||
@vars["_TARGET"] = @target
|
@vars["_TARGET"] = @target
|
||||||
@vars["_SOURCES"] = @sources
|
@vars["_SOURCES"] = @sources
|
||||||
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
@vars["_DEPFILE"] = "#{target}#{env.expand_varref("${DEPFILESUFFIX}", vars)}"
|
||||||
command = @env.build_command("${CPP_CMD}", @vars)
|
command = @env.build_command("${CPP_CMD}", @vars)
|
||||||
self.produces(@vars["_DEPFILE"])
|
self.produces(@vars["_DEPFILE"])
|
||||||
standard_command("Preprocessing <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
|
standard_command("Preprocessing <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ module Rscons
|
|||||||
include Mixins::Program
|
include Mixins::Program
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
# Custom new method which will delegate to the correct class depending
|
||||||
|
# on the options specified.
|
||||||
def new(options, *more)
|
def new(options, *more)
|
||||||
unless File.basename(options[:target])["."]
|
unless File.basename(options[:target])["."]
|
||||||
options[:target] += options[:env].expand_varref("${PROGSUFFIX}", options[:vars])
|
options[:target] += options[:env].expand_varref("${PROGSUFFIX}", options[:vars])
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ module Rscons
|
|||||||
include Mixins::Program
|
include Mixins::Program
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
# Custom new method which will delegate to the correct class depending
|
||||||
|
# on the options specified.
|
||||||
def new(options, *more)
|
def new(options, *more)
|
||||||
libprefix = options[:env].expand_varref("${SHLIBPREFIX}", options[:vars])
|
libprefix = options[:env].expand_varref("${SHLIBPREFIX}", options[:vars])
|
||||||
unless File.basename(options[:target]).start_with?(libprefix)
|
unless File.basename(options[:target]).start_with?(libprefix)
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ module Rscons
|
|||||||
include Mixins::Object
|
include Mixins::Object
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
# Content component to add to build path to separate objects built
|
||||||
|
# using this builder from others.
|
||||||
def extra_path
|
def extra_path
|
||||||
"_shared"
|
"_shared"
|
||||||
end
|
end
|
||||||
|
|||||||
+5
-6
@@ -1,15 +1,18 @@
|
|||||||
require "rscons"
|
require "rscons"
|
||||||
require "optparse"
|
require "optparse"
|
||||||
|
|
||||||
|
# CLI usage string.
|
||||||
USAGE = <<EOF
|
USAGE = <<EOF
|
||||||
Usage: #{$0} [global options] [operation] [operation options]
|
Usage: #{$0} [global options] [operation] [operation options]
|
||||||
|
|
||||||
Global options:
|
Global options:
|
||||||
-F, --show-failure Show previous failed command(s) and exit
|
-f FILE Use FILE as Rsconscript
|
||||||
--version Show rscons version and exit
|
-F, --show-failure Show failed command log from previous build 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
|
||||||
@@ -22,10 +25,6 @@ Operations:
|
|||||||
Configure options:
|
Configure options:
|
||||||
-b BUILD, --build=BUILD Set build directory (default: build)
|
-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
|
||||||
|
|||||||
+246
-153
@@ -5,9 +5,6 @@ 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]
|
||||||
@@ -62,6 +59,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 +70,7 @@ module Rscons
|
|||||||
cc = ccc.find do |cc|
|
cc = ccc.find do |cc|
|
||||||
test_c_compiler(cc)
|
test_c_compiler(cc)
|
||||||
end
|
end
|
||||||
common_config_checks(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 +81,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 +92,7 @@ module Rscons
|
|||||||
cc = ccc.find do |cc|
|
cc = ccc.find do |cc|
|
||||||
test_cxx_compiler(cc)
|
test_cxx_compiler(cc)
|
||||||
end
|
end
|
||||||
common_config_checks(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 +103,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 +114,7 @@ module Rscons
|
|||||||
dc = cdc.find do |dc|
|
dc = cdc.find do |dc|
|
||||||
test_d_compiler(dc)
|
test_d_compiler(dc)
|
||||||
end
|
end
|
||||||
common_config_checks(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.
|
||||||
@@ -122,11 +131,12 @@ module Rscons
|
|||||||
if status == 0
|
if status == 0
|
||||||
store_parse(stdout, options)
|
store_parse(stdout, options)
|
||||||
end
|
end
|
||||||
common_config_checks(status, options)
|
complete(status, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a C header.
|
# Check for a C header.
|
||||||
def check_c_header(header_name, options = {})
|
def check_c_header(header_name, options = {})
|
||||||
|
check_cpppath = [nil] + (options[:check_cpppath] || [])
|
||||||
Ansi.write($stdout, "Checking for C header '", :cyan, header_name, :reset, "'... ")
|
Ansi.write($stdout, "Checking for C header '", :cyan, header_name, :reset, "'... ")
|
||||||
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
|
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
|
||||||
fh.puts <<-EOF
|
fh.puts <<-EOF
|
||||||
@@ -139,15 +149,30 @@ module Rscons
|
|||||||
vars = {
|
vars = {
|
||||||
"LD" => "${CC}",
|
"LD" => "${CC}",
|
||||||
"_SOURCES" => "#{@work_dir}/cfgtest.c",
|
"_SOURCES" => "#{@work_dir}/cfgtest.c",
|
||||||
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
"_TARGET" => "#{@work_dir}/cfgtest.o",
|
||||||
|
"_DEPFILE" => "#{@work_dir}/cfgtest.mf",
|
||||||
}
|
}
|
||||||
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
status = 1
|
||||||
|
check_cpppath.each do |cpppath|
|
||||||
|
env = BasicEnvironment.new
|
||||||
|
if cpppath
|
||||||
|
env["CPPPATH"] += Array(cpppath)
|
||||||
|
end
|
||||||
|
command = env.build_command("${CCCMD}", vars)
|
||||||
_, _, status = log_and_test_command(command)
|
_, _, status = log_and_test_command(command)
|
||||||
common_config_checks(status, options)
|
if status == 0
|
||||||
|
if cpppath
|
||||||
|
store_append({"CPPPATH" => Array(cpppath)}, options)
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
complete(status, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a C++ header.
|
# Check for a C++ header.
|
||||||
def check_cxx_header(header_name, options = {})
|
def check_cxx_header(header_name, options = {})
|
||||||
|
check_cpppath = [nil] + (options[:check_cpppath] || [])
|
||||||
Ansi.write($stdout, "Checking for C++ header '", :cyan, header_name, :reset, "'... ")
|
Ansi.write($stdout, "Checking for C++ header '", :cyan, header_name, :reset, "'... ")
|
||||||
File.open("#{@work_dir}/cfgtest.cxx", "wb") do |fh|
|
File.open("#{@work_dir}/cfgtest.cxx", "wb") do |fh|
|
||||||
fh.puts <<-EOF
|
fh.puts <<-EOF
|
||||||
@@ -160,15 +185,30 @@ module Rscons
|
|||||||
vars = {
|
vars = {
|
||||||
"LD" => "${CXX}",
|
"LD" => "${CXX}",
|
||||||
"_SOURCES" => "#{@work_dir}/cfgtest.cxx",
|
"_SOURCES" => "#{@work_dir}/cfgtest.cxx",
|
||||||
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
"_TARGET" => "#{@work_dir}/cfgtest.o",
|
||||||
|
"_DEPFILE" => "#{@work_dir}/cfgtest.mf",
|
||||||
}
|
}
|
||||||
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
status = 1
|
||||||
|
check_cpppath.each do |cpppath|
|
||||||
|
env = BasicEnvironment.new
|
||||||
|
if cpppath
|
||||||
|
env["CPPPATH"] += Array(cpppath)
|
||||||
|
end
|
||||||
|
command = env.build_command("${CXXCMD}", vars)
|
||||||
_, _, status = log_and_test_command(command)
|
_, _, status = log_and_test_command(command)
|
||||||
common_config_checks(status, options)
|
if status == 0
|
||||||
|
if cpppath
|
||||||
|
store_append({"CPPPATH" => Array(cpppath)}, options)
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
complete(status, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a D import.
|
# Check for a D import.
|
||||||
def check_d_import(d_import, options = {})
|
def check_d_import(d_import, options = {})
|
||||||
|
check_d_import_path = [nil] + (options[:check_d_import_path] || [])
|
||||||
Ansi.write($stdout, "Checking for D import '", :cyan, d_import, :reset, "'... ")
|
Ansi.write($stdout, "Checking for D import '", :cyan, d_import, :reset, "'... ")
|
||||||
File.open("#{@work_dir}/cfgtest.d", "wb") do |fh|
|
File.open("#{@work_dir}/cfgtest.d", "wb") do |fh|
|
||||||
fh.puts <<-EOF
|
fh.puts <<-EOF
|
||||||
@@ -181,15 +221,30 @@ module Rscons
|
|||||||
vars = {
|
vars = {
|
||||||
"LD" => "${DC}",
|
"LD" => "${DC}",
|
||||||
"_SOURCES" => "#{@work_dir}/cfgtest.d",
|
"_SOURCES" => "#{@work_dir}/cfgtest.d",
|
||||||
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
"_TARGET" => "#{@work_dir}/cfgtest.o",
|
||||||
|
"_DEPFILE" => "#{@work_dir}/cfgtest.mf",
|
||||||
}
|
}
|
||||||
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
status = 1
|
||||||
|
check_d_import_path.each do |d_import_path|
|
||||||
|
env = BasicEnvironment.new
|
||||||
|
if d_import_path
|
||||||
|
env["D_IMPORT_PATH"] += Array(d_import_path)
|
||||||
|
end
|
||||||
|
command = env.build_command("${DCCMD}", vars)
|
||||||
_, _, status = log_and_test_command(command)
|
_, _, status = log_and_test_command(command)
|
||||||
common_config_checks(status, options)
|
if status == 0
|
||||||
|
if d_import_path
|
||||||
|
store_append({"D_IMPORT_PATH" => Array(d_import_path)}, options)
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
complete(status, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a library.
|
# Check for a library.
|
||||||
def check_lib(lib, options = {})
|
def check_lib(lib, options = {})
|
||||||
|
check_libpath = [nil] + (options[:check_libpath] || [])
|
||||||
Ansi.write($stdout, "Checking for library '", :cyan, lib, :reset, "'... ")
|
Ansi.write($stdout, "Checking for library '", :cyan, lib, :reset, "'... ")
|
||||||
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
|
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
|
||||||
fh.puts <<-EOF
|
fh.puts <<-EOF
|
||||||
@@ -204,129 +259,49 @@ module Rscons
|
|||||||
"_SOURCES" => "#{@work_dir}/cfgtest.c",
|
"_SOURCES" => "#{@work_dir}/cfgtest.c",
|
||||||
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
||||||
}
|
}
|
||||||
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
status = 1
|
||||||
|
check_libpath.each do |libpath|
|
||||||
|
env = BasicEnvironment.new
|
||||||
|
if libpath
|
||||||
|
env["LIBPATH"] += Array(libpath)
|
||||||
|
end
|
||||||
|
command = env.build_command("${LDCMD}", vars)
|
||||||
_, _, status = log_and_test_command(command)
|
_, _, status = log_and_test_command(command)
|
||||||
|
if status == 0
|
||||||
|
if libpath
|
||||||
|
store_append({"LIBPATH" => Array(libpath)}, options)
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
if status == 0
|
if status == 0
|
||||||
store_append({"LIBS" => [lib]}, options)
|
store_append({"LIBS" => [lib]}, options)
|
||||||
end
|
end
|
||||||
common_config_checks(status, options)
|
complete(status, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a executable program.
|
# Check for a executable program.
|
||||||
def check_program(program, options = {})
|
def check_program(program, options = {})
|
||||||
Ansi.write($stdout, "Checking for program '", :cyan, program, :reset, "'... ")
|
Ansi.write($stdout, "Checking for program '", :cyan, program, :reset, "'... ")
|
||||||
path = Util.find_executable(program)
|
path = Util.find_executable(program)
|
||||||
common_config_checks(path ? 0 : 1, options.merge(success_message: path))
|
complete(path ? 0 : 1, options.merge(success_message: path))
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# Test a C compiler.
|
|
||||||
#
|
|
||||||
# @param cc [String]
|
|
||||||
# C compiler to test.
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
# Whether the C compiler tested successfully.
|
|
||||||
def test_c_compiler(cc)
|
|
||||||
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
|
|
||||||
fh.puts <<-EOF
|
|
||||||
#include <stdio.h>
|
|
||||||
int main(int argc, char * argv[]) {
|
|
||||||
printf("Success.\\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
command = %W[#{cc} -o #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.c]
|
|
||||||
merge = {"CC" => cc}
|
|
||||||
_, _, status = log_and_test_command(command)
|
|
||||||
if status == 0
|
|
||||||
stdout, _, status = log_and_test_command(["#{@work_dir}/cfgtest.exe"])
|
|
||||||
if status == 0 and stdout =~ /Success/
|
|
||||||
store_merge(merge)
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Test a C++ compiler.
|
|
||||||
#
|
|
||||||
# @param cc [String]
|
|
||||||
# C++ compiler to test.
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
# Whether the C++ compiler tested successfully.
|
|
||||||
def test_cxx_compiler(cc)
|
|
||||||
File.open("#{@work_dir}/cfgtest.cxx", "wb") do |fh|
|
|
||||||
fh.puts <<-EOF
|
|
||||||
#include <iostream>
|
|
||||||
using namespace std;
|
|
||||||
int main(int argc, char * argv[]) {
|
|
||||||
cout << "Success." << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
command = %W[#{cc} -o #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.cxx]
|
|
||||||
merge = {"CXX" => cc}
|
|
||||||
_, _, status = log_and_test_command(command)
|
|
||||||
if status == 0
|
|
||||||
stdout, _, status = log_and_test_command(["#{@work_dir}/cfgtest.exe"])
|
|
||||||
if status == 0 and stdout =~ /Success/
|
|
||||||
store_merge(merge)
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Test a D compiler.
|
|
||||||
#
|
|
||||||
# @param dc [String]
|
|
||||||
# D compiler to test.
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
# Whether the D compiler tested successfully.
|
|
||||||
def test_d_compiler(dc)
|
|
||||||
File.open("#{@work_dir}/cfgtest.d", "wb") do |fh|
|
|
||||||
fh.puts <<-EOF
|
|
||||||
import std.stdio;
|
|
||||||
int main() {
|
|
||||||
writeln("Success.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
[:gdc, :ldc2].find do |dc_test|
|
|
||||||
case dc_test
|
|
||||||
when :gdc
|
|
||||||
command = %W[#{dc} -o #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.d]
|
|
||||||
merge = {"DC" => dc}
|
|
||||||
when :ldc2
|
|
||||||
command = %W[#{dc} -of #{@work_dir}/cfgtest.exe #{@work_dir}/cfgtest.d]
|
|
||||||
env = BasicEnvironment.new
|
|
||||||
merge = {
|
|
||||||
"DC" => dc,
|
|
||||||
"DCCMD" => env["DCCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
|
|
||||||
"LDCMD" => env["LDCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
|
|
||||||
}
|
|
||||||
end
|
|
||||||
_, _, status = log_and_test_command(command)
|
|
||||||
if status == 0
|
|
||||||
stdout, _, status = log_and_test_command(["#{@work_dir}/cfgtest.exe"])
|
|
||||||
if status == 0 and stdout =~ /Success/
|
|
||||||
store_merge(merge)
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Execute a test command and log the result.
|
# Execute a test command and log the result.
|
||||||
def log_and_test_command(command)
|
#
|
||||||
|
# @param command [Array<String>]
|
||||||
|
# Command to execute.
|
||||||
|
# @param options [Hash]
|
||||||
|
# Optional arguments.
|
||||||
|
# @option options [String] :stdin
|
||||||
|
# Data to send to standard input stream of the executed command.
|
||||||
|
#
|
||||||
|
# @return [String, String, Process::Status]
|
||||||
|
# stdout, stderr, status
|
||||||
|
def log_and_test_command(command, options = {})
|
||||||
begin
|
begin
|
||||||
@log_fh.puts("Command: #{command.join(" ")}")
|
@log_fh.puts("Command: #{command.join(" ")}")
|
||||||
stdout, stderr, status = Open3.capture3(*command)
|
stdout, stderr, status = Open3.capture3(*command, stdin_data: options[:stdin])
|
||||||
@log_fh.puts("Exit status: #{status.to_i}")
|
@log_fh.puts("Exit status: #{status.to_i}")
|
||||||
@log_fh.write(stdout)
|
@log_fh.write(stdout)
|
||||||
@log_fh.write(stderr)
|
@log_fh.write(stderr)
|
||||||
@@ -342,6 +317,10 @@ module Rscons
|
|||||||
# Hash containing the variables to merge.
|
# Hash containing the variables to merge.
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# Options.
|
# Options.
|
||||||
|
# @option options [String] :use
|
||||||
|
# A 'use' name. If specified, the construction variables are only applied
|
||||||
|
# to an Environment if the Environment is constructed with a matching
|
||||||
|
# `:use` value.
|
||||||
def store_merge(vars, options = {})
|
def store_merge(vars, options = {})
|
||||||
store_vars = store_common(options)
|
store_vars = store_common(options)
|
||||||
store_vars["merge"] ||= {}
|
store_vars["merge"] ||= {}
|
||||||
@@ -356,6 +335,10 @@ module Rscons
|
|||||||
# Hash containing the variables to append.
|
# Hash containing the variables to append.
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# Options.
|
# Options.
|
||||||
|
# @option options [String] :use
|
||||||
|
# A 'use' name. If specified, the construction variables are only applied
|
||||||
|
# to an Environment if the Environment is constructed with a matching
|
||||||
|
# `:use` value.
|
||||||
def store_append(vars, options = {})
|
def store_append(vars, options = {})
|
||||||
store_vars = store_common(options)
|
store_vars = store_common(options)
|
||||||
store_vars["append"] ||= {}
|
store_vars["append"] ||= {}
|
||||||
@@ -374,12 +357,151 @@ module Rscons
|
|||||||
# String containing the flags to parse.
|
# String containing the flags to parse.
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# Options.
|
# Options.
|
||||||
|
# @option options [String] :use
|
||||||
|
# A 'use' name. If specified, the construction variables are only applied
|
||||||
|
# to an Environment if the Environment is constructed with a matching
|
||||||
|
# `:use` value.
|
||||||
def store_parse(flags, options = {})
|
def store_parse(flags, options = {})
|
||||||
store_vars = store_common(options)
|
store_vars = store_common(options)
|
||||||
store_vars["parse"] ||= []
|
store_vars["parse"] ||= []
|
||||||
store_vars["parse"] << flags
|
store_vars["parse"] << flags
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Perform processing common to several configure checks.
|
||||||
|
#
|
||||||
|
# @param status [Process::Status, Integer]
|
||||||
|
# Process exit code. 0 for success, non-zero for error.
|
||||||
|
# @param options [Hash]
|
||||||
|
# Common check options.
|
||||||
|
# @option options [Boolean] :fail
|
||||||
|
# Whether to fail configuration if the requested item is not found.
|
||||||
|
# This defaults to true if the :set_define option is not specified,
|
||||||
|
# otherwise defaults to false if :set_define option is specified.
|
||||||
|
# @option options [String] :set_define
|
||||||
|
# A define to set (in CPPDEFINES) if the requested item is found.
|
||||||
|
# @option options [String] :success_message
|
||||||
|
# Message to print on success (default "found").
|
||||||
|
def complete(status, options)
|
||||||
|
success_message = options[:success_message] || "found"
|
||||||
|
fail_message = options[:fail_message] || "not found"
|
||||||
|
if status == 0
|
||||||
|
Ansi.write($stdout, :green, "#{success_message}\n")
|
||||||
|
if options[:set_define]
|
||||||
|
store_append("CPPDEFINES" => [options[:set_define]])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
should_fail =
|
||||||
|
if options.has_key?(:fail)
|
||||||
|
options[:fail]
|
||||||
|
else
|
||||||
|
!options[:set_define]
|
||||||
|
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
|
||||||
|
raise RsconsError.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Test a C compiler.
|
||||||
|
#
|
||||||
|
# @param cc [String]
|
||||||
|
# C compiler to test.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
# Whether the C compiler tested successfully.
|
||||||
|
def test_c_compiler(cc)
|
||||||
|
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
|
||||||
|
fh.puts <<-EOF
|
||||||
|
int fun(int val) {
|
||||||
|
return val * 2;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
command = %W[#{cc} -c -o #{@work_dir}/cfgtest.o #{@work_dir}/cfgtest.c]
|
||||||
|
merge = {"CC" => cc}
|
||||||
|
_, _, status = log_and_test_command(command)
|
||||||
|
if status == 0
|
||||||
|
store_merge(merge)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Test a C++ compiler.
|
||||||
|
#
|
||||||
|
# @param cc [String]
|
||||||
|
# C++ compiler to test.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
# Whether the C++ compiler tested successfully.
|
||||||
|
def test_cxx_compiler(cc)
|
||||||
|
File.open("#{@work_dir}/cfgtest.cxx", "wb") do |fh|
|
||||||
|
fh.puts <<-EOF
|
||||||
|
template<typename T>
|
||||||
|
T fun(T val) {
|
||||||
|
return val * 2;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
command = %W[#{cc} -c -o #{@work_dir}/cfgtest.o #{@work_dir}/cfgtest.cxx]
|
||||||
|
merge = {"CXX" => cc}
|
||||||
|
_, _, status = log_and_test_command(command)
|
||||||
|
if status == 0
|
||||||
|
store_merge(merge)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Test a D compiler.
|
||||||
|
#
|
||||||
|
# @param dc [String]
|
||||||
|
# D compiler to test.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
# Whether the D compiler tested successfully.
|
||||||
|
def test_d_compiler(dc)
|
||||||
|
File.open("#{@work_dir}/cfgtest.d", "wb") do |fh|
|
||||||
|
fh.puts <<-EOF
|
||||||
|
import core.math;
|
||||||
|
int fun() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
[:gdc, :ldc2].find do |dc_test|
|
||||||
|
case dc_test
|
||||||
|
when :gdc
|
||||||
|
command = %W[#{dc} -c -o #{@work_dir}/cfgtest.o #{@work_dir}/cfgtest.d]
|
||||||
|
merge = {"DC" => dc}
|
||||||
|
when :ldc2
|
||||||
|
# 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
|
||||||
|
merge = {
|
||||||
|
"DC" => dc,
|
||||||
|
"DCCMD" => env["DCCMD"].map {|e| e.sub(/^-o$/, "-of")},
|
||||||
|
"LDCMD" => env["LDCMD"].map {|e| e.sub(/^-o$/, "-of")},
|
||||||
|
"DDEPGEN" => ["-deps=${_DEPFILE}"],
|
||||||
|
}
|
||||||
|
merge["OBJSUFFIX"] = [ldc_objsuffix]
|
||||||
|
end
|
||||||
|
_, _, status = log_and_test_command(command)
|
||||||
|
if status == 0
|
||||||
|
store_merge(merge)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Common functionality for all store methods.
|
# Common functionality for all store methods.
|
||||||
#
|
#
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
@@ -403,34 +525,5 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Perform processing common to several configure checks.
|
|
||||||
#
|
|
||||||
# @param status [Process::Status, Integer]
|
|
||||||
# Process exit code.
|
|
||||||
# @param options [Hash]
|
|
||||||
# Common check options.
|
|
||||||
# @option options [Boolean] :fail
|
|
||||||
# Whether to fail configuration if the requested item is not found.
|
|
||||||
# @option options [String] :set_define
|
|
||||||
# A define to set (in CPPDEFINES) if the requested item is found.
|
|
||||||
# @option options [String] :success_message
|
|
||||||
# Message to print on success (default "found").
|
|
||||||
def common_config_checks(status, options)
|
|
||||||
success_message = options[:success_message] || "found"
|
|
||||||
if status == 0
|
|
||||||
Ansi.write($stdout, :green, "#{success_message}\n")
|
|
||||||
if options[:set_define]
|
|
||||||
store_append("CPPDEFINES" => [options[:set_define]])
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if options.has_key?(:fail) and not options[:fail]
|
|
||||||
Ansi.write($stdout, :yellow, "not found\n")
|
|
||||||
else
|
|
||||||
Ansi.write($stdout, :red, "not found\n")
|
|
||||||
raise ConfigureFailure.new
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -59,6 +58,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, Array<String>] :use
|
||||||
|
# Use flag(s). If specified, any configuration flags which were saved
|
||||||
|
# with a corresponding `:use` value will be applied to this Environment.
|
||||||
#
|
#
|
||||||
# If a block is given, the Environment object is yielded to the block and
|
# If a block is given, the Environment object is yielded to the block and
|
||||||
# when the block returns, the {#process} method is automatically called.
|
# when the block returns, the {#process} method is automatically called.
|
||||||
@@ -248,7 +250,7 @@ module Rscons
|
|||||||
if extra_path = builder_class.extra_path
|
if extra_path = builder_class.extra_path
|
||||||
extra_path = "/#{extra_path}"
|
extra_path = "/#{extra_path}"
|
||||||
end
|
end
|
||||||
"#{@build_root}#{extra_path}/#{Util.make_relative_path(Rscons.set_suffix(source_fname, suffix))}".gsub("\\", "/")
|
"#{@build_root}#{extra_path}/#{Util.make_relative_path("#{source_fname}#{suffix}")}".gsub("\\", "/")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Build all build targets specified in the Environment.
|
# Build all build targets specified in the Environment.
|
||||||
@@ -284,9 +286,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 += "\nRun `#{$0} -F` to see the failed command(s)."
|
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
|
||||||
|
|
||||||
@@ -344,12 +346,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
|
||||||
@@ -699,10 +701,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
|
||||||
|
|
||||||
|
|||||||
+96
-2
@@ -3,7 +3,87 @@ 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
|
||||||
|
|
||||||
class Dsl
|
# Global DSL methods.
|
||||||
|
class GlobalDsl
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# Top-level DSL available to the Rsconscript.
|
||||||
|
class Dsl < GlobalDsl
|
||||||
# Create a Dsl.
|
# Create a Dsl.
|
||||||
def initialize(script)
|
def initialize(script)
|
||||||
@script = script
|
@script = script
|
||||||
@@ -57,7 +137,8 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class ConfigureDsl
|
# DSL available to the 'configure' block.
|
||||||
|
class ConfigureDsl < GlobalDsl
|
||||||
# Create a ConfigureDsl.
|
# Create a ConfigureDsl.
|
||||||
#
|
#
|
||||||
# @param configure_op [ConfigureOp]
|
# @param configure_op [ConfigureOp]
|
||||||
@@ -81,6 +162,19 @@ module Rscons
|
|||||||
@configure_op.__send__(method_name, *args)
|
@configure_op.__send__(method_name, *args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Perform a custom configuration check.
|
||||||
|
#
|
||||||
|
# @param message [String]
|
||||||
|
# Custom configuration check message (e.g. "Checking for foo").
|
||||||
|
# rscons will add "... " to the end of the message.
|
||||||
|
# @yieldparam configure_op [ConfigureOp]
|
||||||
|
# {ConfigureOp} object.
|
||||||
|
# @return [void]
|
||||||
|
def custom_check(message, &block)
|
||||||
|
$stdout.write(message + "... ")
|
||||||
|
block[@configure_op]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [String, nil]
|
# @return [String, nil]
|
||||||
|
|||||||
+51
-7
@@ -1,4 +1,5 @@
|
|||||||
module Rscons
|
module Rscons
|
||||||
|
# A collection of stand-alone utility methods.
|
||||||
module Util
|
module Util
|
||||||
class << self
|
class << self
|
||||||
|
|
||||||
@@ -8,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?("/")
|
||||||
@@ -67,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/
|
||||||
@@ -159,7 +160,7 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Parse dependencies from a Makefile.
|
# Parse dependencies from a Makefile or ldc2 dependency file.
|
||||||
#
|
#
|
||||||
# This method is used internally by Rscons builders.
|
# This method is used internally by Rscons builders.
|
||||||
#
|
#
|
||||||
@@ -168,7 +169,7 @@ module Rscons
|
|||||||
#
|
#
|
||||||
# @return [Array<String>]
|
# @return [Array<String>]
|
||||||
# Paths of dependency files.
|
# Paths of dependency files.
|
||||||
def parse_makefile_deps(mf_fname)
|
def parse_dependency_file(mf_fname)
|
||||||
deps = []
|
deps = []
|
||||||
buildup = ''
|
buildup = ''
|
||||||
File.read(mf_fname).each_line do |line|
|
File.read(mf_fname).each_line do |line|
|
||||||
@@ -176,7 +177,11 @@ module Rscons
|
|||||||
buildup += ' ' + $1
|
buildup += ' ' + $1
|
||||||
else
|
else
|
||||||
buildup += ' ' + line
|
buildup += ' ' + line
|
||||||
if buildup =~ /^.*: (.*)$/
|
if buildup =~ /^[^:]+\(\S+\)\s*:.*?:[^:]+\((\S+)\)/
|
||||||
|
# ldc2-style dependency line
|
||||||
|
deps << $1
|
||||||
|
elsif buildup =~ /^.*: (.*)$/
|
||||||
|
# Makefile-style dependency line
|
||||||
mf_deps = $1
|
mf_deps = $1
|
||||||
deps += mf_deps.split(' ').map(&:strip)
|
deps += mf_deps.split(' ').map(&:strip)
|
||||||
end
|
end
|
||||||
@@ -186,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.
|
||||||
@@ -194,11 +233,15 @@ 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)
|
||||||
executable = executable.downcase
|
executable = executable.downcase
|
||||||
dir_entries = Dir.entries(path_entry)
|
dir_entries = Dir.entries(path_entry)
|
||||||
dir_entries.find do |entry|
|
dir_entries.find do |entry|
|
||||||
@@ -211,6 +254,7 @@ module Rscons
|
|||||||
return path
|
return path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
else
|
else
|
||||||
path = "#{path_entry}/#{executable}"
|
path = "#{path_entry}/#{executable}"
|
||||||
return path if is_executable[path]
|
return path if is_executable[path]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module Rscons
|
module Rscons
|
||||||
# Project version.
|
# Project version.
|
||||||
VERSION = "2.0.0beta1"
|
VERSION = "2.3.0"
|
||||||
end
|
end
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>RScons User Guide<%= subpage_title %> - Version <%= Rscons::VERSION %></title>
|
<title>Rscons User Guide<%= subpage_title %> - Version <%= Rscons::VERSION %></title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
background-color: #CCC;
|
background-color: #CCC;
|
||||||
@@ -31,6 +31,11 @@
|
|||||||
.separator {
|
.separator {
|
||||||
height: 2em;
|
height: 2em;
|
||||||
}
|
}
|
||||||
|
.img_block_center {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
.page_nav {
|
.page_nav {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
|
|||||||
+13
-9
@@ -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,15 +53,18 @@ 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"
|
||||||
compressed_script = Zlib::Deflate.deflate(stripped_comments.join)
|
require "base64"
|
||||||
escaped_compressed_script = compressed_script.gsub("#", "#1").gsub("\n", "#2").gsub("\r", "#3").gsub("\0", "#4")
|
compressed_script = Zlib::Deflate.deflate(stripped.join)
|
||||||
hash = Digest::MD5.hexdigest(escaped_compressed_script)
|
encoded_compressed_script = Base64.encode64(compressed_script).gsub("\n", "")
|
||||||
|
hash = Digest::MD5.hexdigest(encoded_compressed_script)
|
||||||
|
|
||||||
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|
|
||||||
@@ -70,9 +73,10 @@ File.open("#{DIST}/#{PROG_NAME}", "wb", 0755) do |fh|
|
|||||||
script = File.join(File.dirname(__FILE__), ".rscons-#{VERSION}-#{hash}.rb")
|
script = File.join(File.dirname(__FILE__), ".rscons-#{VERSION}-#{hash}.rb")
|
||||||
unless File.exists?(script)
|
unless File.exists?(script)
|
||||||
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
|
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
|
||||||
escaped_compressed = $1
|
|
||||||
unescaped_compressed = escaped_compressed.gsub("#4", "\\0").gsub("#3", "\\r").gsub("#2", "\\n").gsub("#1", "#")
|
|
||||||
require "zlib"
|
require "zlib"
|
||||||
|
require "base64"
|
||||||
|
encoded_compressed = $1
|
||||||
|
unescaped_compressed = Base64.decode64(encoded_compressed)
|
||||||
inflated = Zlib::Inflate.inflate(unescaped_compressed)
|
inflated = Zlib::Inflate.inflate(unescaped_compressed)
|
||||||
File.open(script, "wb") do |fh|
|
File.open(script, "wb") do |fh|
|
||||||
fh.write(inflated)
|
fh.write(inflated)
|
||||||
@@ -85,6 +89,6 @@ load script
|
|||||||
if __FILE__ == $0
|
if __FILE__ == $0
|
||||||
Rscons::Cli.run(ARGV)
|
Rscons::Cli.run(ARGV)
|
||||||
end
|
end
|
||||||
#==>#{escaped_compressed_script}
|
#==>#{encoded_compressed_script}
|
||||||
EOF
|
EOF
|
||||||
end
|
end
|
||||||
+14
-1
@@ -59,6 +59,8 @@ class Generator
|
|||||||
line = @lines.slice!(0)
|
line = @lines.slice!(0)
|
||||||
if line =~ /^```(.*)$/
|
if line =~ /^```(.*)$/
|
||||||
@sections.last.append(gather_code_section($1))
|
@sections.last.append(gather_code_section($1))
|
||||||
|
elsif line.chomp == "${remove}"
|
||||||
|
remove_section
|
||||||
elsif line =~ /^(#+)(>)?\s*(.*)$/
|
elsif line =~ /^(#+)(>)?\s*(.*)$/
|
||||||
level_text, new_page_text, title_text = $1, $2, $3
|
level_text, new_page_text, title_text = $1, $2, $3
|
||||||
level = $1.size
|
level = $1.size
|
||||||
@@ -152,7 +154,8 @@ class Generator
|
|||||||
end
|
end
|
||||||
|
|
||||||
def render_toc
|
def render_toc
|
||||||
toc_content = %[<h1>Table of Contents</h1>\n]
|
toc_content = %[<img class="img_block_center" src="rscons_logo_1000.png" />]
|
||||||
|
toc_content += %[<h1>Table of Contents</h1>\n]
|
||||||
@sections.each do |section|
|
@sections.each do |section|
|
||||||
indent = section.number.split(".").size - 1
|
indent = section.number.split(".").size - 1
|
||||||
toc_content += %[<span style="padding-left: #{4 * indent}ex;">]
|
toc_content += %[<span style="padding-left: #{4 * indent}ex;">]
|
||||||
@@ -196,6 +199,15 @@ class Generator
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_section
|
||||||
|
loop do
|
||||||
|
line = @lines.slice!(0)
|
||||||
|
if line.chomp == "${/remove}"
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_next_section_number(level)
|
def get_next_section_number(level)
|
||||||
if @current_section_number.size == level - 1
|
if @current_section_number.size == level - 1
|
||||||
@current_section_number << 1
|
@current_section_number << 1
|
||||||
@@ -212,5 +224,6 @@ end
|
|||||||
input = load_file("doc/user_guide.md")
|
input = load_file("doc/user_guide.md")
|
||||||
FileUtils.rm_rf("gen/user_guide")
|
FileUtils.rm_rf("gen/user_guide")
|
||||||
FileUtils.mkdir_p("gen/user_guide")
|
FileUtils.mkdir_p("gen/user_guide")
|
||||||
|
FileUtils.cp("img/rscons_logo_1000.png", "gen/user_guide")
|
||||||
Generator.new(input, "gen/user_guide/user_guide.html", false)
|
Generator.new(input, "gen/user_guide/user_guide.html", false)
|
||||||
Generator.new(input, "gen/user_guide", true)
|
Generator.new(input, "gen/user_guide", true)
|
||||||
+494
-120
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||||
@@ -121,7 +121,10 @@ EOF
|
|||||||
before(:each) do
|
before(:each) do
|
||||||
stub_const("File::PATH_SEPARATOR", ";")
|
stub_const("File::PATH_SEPARATOR", ";")
|
||||||
stub_const("RbConfig::CONFIG", "host_os" => "mingw")
|
stub_const("RbConfig::CONFIG", "host_os" => "mingw")
|
||||||
expect(ENV).to receive(:[]).with("PATH").and_return("C:\\bin;C:\\Windows")
|
expect(ENV).to receive(:[]).with("PATH").and_return("C:\\none;C:\\bin;C:\\Windows")
|
||||||
|
allow(File).to receive(:directory?).with("C:\\none").and_return(false)
|
||||||
|
allow(File).to receive(:directory?).with("C:\\bin").and_return(true)
|
||||||
|
allow(File).to receive(:directory?).with("C:\\Windows").and_return(true)
|
||||||
allow(Dir).to receive(:entries).with("C:\\bin").and_return(%w[one.com])
|
allow(Dir).to receive(:entries).with("C:\\bin").and_return(%w[one.com])
|
||||||
allow(Dir).to receive(:entries).with("C:\\Windows").and_return(%w[two.exe Three.bat])
|
allow(Dir).to receive(:entries).with("C:\\Windows").and_return(%w[two.exe Three.bat])
|
||||||
end
|
end
|
||||||
@@ -197,12 +200,12 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".parse_makefile_deps" do
|
describe ".parse_dependency_file" do
|
||||||
it 'handles dependencies on one line' do
|
it 'handles dependencies on one line' do
|
||||||
expect(File).to receive(:read).with('makefile').and_return(<<EOS)
|
expect(File).to receive(:read).with('makefile').and_return(<<EOS)
|
||||||
module.o: source.cc
|
module.o: source.cc
|
||||||
EOS
|
EOS
|
||||||
expect(Util.parse_makefile_deps('makefile')).to eq ['source.cc']
|
expect(Util.parse_dependency_file('makefile')).to eq ['source.cc']
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'handles dependencies split across many lines' do
|
it 'handles dependencies split across many lines' do
|
||||||
@@ -211,9 +214,22 @@ module.o: module.c \\
|
|||||||
module.h \\
|
module.h \\
|
||||||
other.h
|
other.h
|
||||||
EOS
|
EOS
|
||||||
expect(Util.parse_makefile_deps('makefile')).to eq [
|
expect(Util.parse_dependency_file('makefile')).to eq [
|
||||||
'module.c', 'module.h', 'other.h']
|
'module.c', 'module.h', 'other.h']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "parses ldc2-style dependency lines" do
|
||||||
|
expect(File).to receive(:read).with("deps.out").and_return(<<EOS)
|
||||||
|
std.traits (/usr/lib/ldc/x86_64-linux-gnu/include/d/std/traits.d) : private : std.meta (/usr/lib/ldc/x86_64-linux-gnu/include/d/std/meta.d):staticIndexOf
|
||||||
|
std.conv (/usr/lib/ldc/x86_64-linux-gnu/include/d/std/conv.d) : private : std.array (/usr/lib/ldc/x86_64-linux-gnu/include/d/std/array.d):array
|
||||||
|
std.stdio (/usr/lib/ldc/x86_64-linux-gnu/include/d/std/stdio.d) : private static : core.sys.posix.sys.socket (/usr/lib/ldc/x86_64-linux-gnu/include/d/core/sys/posix/sys/socket.d) -> sock
|
||||||
|
EOS
|
||||||
|
expect(Util.parse_dependency_file("deps.out")).to eq [
|
||||||
|
"/usr/lib/ldc/x86_64-linux-gnu/include/d/std/meta.d",
|
||||||
|
"/usr/lib/ldc/x86_64-linux-gnu/include/d/std/array.d",
|
||||||
|
"/usr/lib/ldc/x86_64-linux-gnu/include/d/core/sys/posix/sys/socket.d",
|
||||||
|
]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,15 +1,5 @@
|
|||||||
describe Rscons do
|
describe Rscons do
|
||||||
|
|
||||||
describe ".set_suffix" do
|
|
||||||
it "changes the suffix to the new one" do
|
|
||||||
expect(Rscons.set_suffix("foo.c", ".h")).to eq("foo.h")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "appends a suffix if the given file name does not have one" do
|
|
||||||
expect(Rscons.set_suffix("bazz", ".d")).to eq("bazz.d")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ".get_system_shell" do
|
describe ".get_system_shell" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
Rscons.instance_variable_set(:@shell, nil)
|
Rscons.instance_variable_set(:@shell, nil)
|
||||||
|
|||||||
+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