Compare commits

..
86 Commits
Author SHA1 Message Date
josh a2f72c6b87 v2.3.0 2021-12-04 09:43:03 -05:00
josh 7055cad73c Add v2.3.0 release notes 2021-12-04 09:27:24 -05:00
josh 4548f4e3c9 Document phony targets - close #141 2021-12-01 23:00:12 -05:00
josh 19dbab3426 Run subsidiary rscons binary from rscons() method if found - close #129 2021-11-28 22:36:24 -05:00
josh 69f5bea2b2 Fix specs for dependency file moving - #135 2021-11-28 15:10:25 -05:00
josh 2ee9dda49d Write dependency file to build directory when user invokes Object builder directly - close #135 2021-11-18 20:18:19 -05:00
josh f011b23499 Add PATH manipulation methods - close #126 2021-11-17 21:39:58 -05:00
josh 80d52f25b8 Document CMD_STDOUT variable for Command builder - close #134 2021-11-15 21:52:11 -05:00
josh 0face546e3 Clarify failed command error message indicating to run -F - close #133 2021-11-15 21:45:18 -05:00
josh ca747232cd Support passing a directory to rscons() method - close #128 2021-11-13 11:36:25 -05:00
josh a7b46093e9 Document -f command line option - close #130 2021-11-13 11:07:15 -05:00
josh 09892eed63 Add DEVELOPING.md 2021-11-07 21:09:42 -05:00
josh 117df43f64 Document rscons() build script method for subsidiary build scripts 2021-10-27 23:02:04 -04:00
josh acc12822b6 Add description for user_guide task 2021-10-27 22:42:31 -04:00
josh 8c7b43f60c Show a message when entering/leaving a subsidiary script directory 2021-10-22 16:48:44 -04:00
josh 7c8becc3f9 env.depends() does not work with build-root-relative "^/" paths - close #121 2021-10-22 16:03:10 -04:00
josh d1a35501ef Support subsidiary Rsconscript files - close #125 2021-10-22 13:58:38 -04:00
josh 28a245f0ab build_dist: Remove lines marked just for specs 2021-10-22 13:58:38 -04:00
josh 87a6d9f04f Do not run simplecov on dspec specs 2021-10-22 13:58:38 -04:00
josh 556c821cc6 Commonize error handling across all operations 2021-10-21 18:35:58 -04:00
josh 441fc9bc65 bundle update 2021-09-02 15:37:33 -04:00
josh 1861874f5c bundle update 2021-01-11 15:15:42 -05:00
dependabot[bot] 6d51c5cbde Bump redcarpet from 3.5.0 to 3.5.1
Bumps [redcarpet](https://github.com/vmg/redcarpet) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/vmg/redcarpet/releases)
- [Changelog](https://github.com/vmg/redcarpet/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vmg/redcarpet/compare/v3.5.0...v3.5.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-01-11 19:21:14 +00:00
josh 73af83803a add v2.2.0 release notes 2020-10-13 19:04:29 -04:00
josh 353f4f45bc v2.2.0 2020-10-13 18:59:18 -04:00
josh 5bac91f92f add failure messages for failed configuration checks - close #119 2020-10-12 21:01:04 -04:00
josh bbe9563ceb compiler checks should support cross-compilers and freestanding compilers - close #118 2020-10-08 19:23:17 -04:00
josh 5ec74604c6 improve support for MSYS2 - close #120 2020-10-08 19:04:50 -04:00
josh 8e06efe61e v2.1.0 2020-04-16 16:52:58 -04:00
josh 0756874ddb update CHANGELOG for v2.1.0 2020-04-16 16:51:16 -04:00
josh dded5e2648 ruby 2.7 compatibility - #117 2020-04-16 15:48:45 -04:00
josh fbe60f6ba2 stick with simplecov 0.15.x for now 2020-04-16 15:02:01 -04:00
josh 8dd9799666 Revert "update simplecov"
This reverts commit 01ca86de8b.
2020-04-16 15:02:01 -04:00
josh f2c755c8bb update bundle 2020-04-16 13:07:20 -04:00
josh 01ca86de8b update simplecov 2020-02-29 14:27:21 -05:00
josh 943fabd0d1 update some gems 2020-02-29 10:47:46 -05:00
josh d08e2f6b5c v2.0.2 2019-12-16 21:36:38 -05:00
josh 90365dd197 update CHANGELOG for v2.0.2 2019-12-16 21:36:22 -05:00
josh 8d05516c40 distinguish object files built from multiple sources with the same base name but different extensions - close #113 2019-12-14 00:10:42 -05:00
josh db49d86866 show a configuration failed message on stderr on configuration failure 2019-10-14 22:57:49 -04:00
josh e667455c32 user guide: fix configure script example 2019-10-14 22:49:34 -04:00
josh e62332aba6 avoid backtrace when configuring fails during autoconf 2019-10-14 22:23:18 -04:00
josh 397639849d call print_run_message() in json_to_yaml build test 2019-10-12 17:59:08 -04:00
josh 96d5caf2e5 user guide: fix print_run_message() examples 2019-10-12 17:57:58 -04:00
josh f4b10a30af update CHANGELOG for v2.0.1 2019-10-02 21:10:29 -04:00
josh cf52c3fc6f v2.0.1 2019-10-02 20:59:58 -04:00
josh 5378afb6f8 Install builder cannot replace a currently executing binary on Linux - close #112 2019-09-28 23:18:31 -04:00
josh 48d9273cc6 v2.0.0 2019-09-11 23:32:27 -04:00
josh efea4f1181 user guide: Installation: mention marking rscons executable 2019-09-11 23:29:25 -04:00
josh b4fa6d965c CHANGELOG - add logo 2019-09-11 23:25:19 -04:00
josh ac56ad34f6 add rscons logo to README 2019-09-11 23:24:20 -04:00
josh 2fd533a32a clobber large_project directory 2019-09-11 23:20:22 -04:00
josh c938ed71d1 add "all" rake task 2019-09-11 23:19:46 -04:00
josh ec60201a62 user guide: add rscons logo 2019-09-11 23:18:38 -04:00
josh 0cafb8c5b3 user guide: stylize as "Rscons" 2019-09-11 23:15:16 -04:00
josh 004810386b clobber should remove "gen" directory 2019-09-11 23:15:02 -04:00
josh a15ee9daaf add logo images 2019-09-11 23:02:17 -04:00
josh cd33405697 user guide: add FreeBSD compatibility 2019-09-01 21:52:32 -04:00
josh efa77066bf allow ConfigureOp#log_and_test_command to be passed standard input data - close #111 2019-09-01 21:50:57 -04:00
josh a1bb9d81fd check_program: do not fail on Windows for non-existent PATH entries 2019-08-27 19:47:21 -04:00
josh 0344f02cb1 build tests: use -m instead of -lc for mingw 2019-08-27 19:32:36 -04:00
josh d52bdaf046 build tests: do ldc2 tests even if omit_gdc_tests set 2019-08-27 18:51:56 -04:00
josh ad7ccb771d update build test for gdc fix 2019-08-27 18:50:01 -04:00
josh 044ee343ca Use OBJSUFFIX of .obj for ldc2 on Windows. 2019-08-26 19:10:19 -04:00
josh eb54a2b64a fix specs create_exe() on Windows 2019-08-26 18:51:03 -04:00
josh 2dd1ce9f1d Use base64 encoding for compressed script to avoid encoding issues. 2019-08-26 18:33:42 -04:00
josh 1e157c79ec fix dependency parsing with ldc2 - close #110 2019-08-19 22:56:54 -04:00
josh 2385874f4a v2.0.0beta2 2019-08-17 17:07:59 -04:00
josh c5c42e6f4a user guide: document a couple missing configure flags and link to YARD some places 2019-08-17 17:00:36 -04:00
josh 9a627b2150 add YARD comments to get to 100% YARD coverage 2019-08-17 16:42:14 -04:00
josh 937c964c3e document :use better 2019-08-17 16:35:06 -04:00
josh a2a1d08014 user guide: document Custom Configuration Checks 2019-08-17 16:35:06 -04:00
josh 0ccf43cc96 custom config checks - close #108 2019-08-17 16:06:37 -04:00
josh d202e15a57 user guide: document direct mode for Program/SharedLibrary builders 2019-07-29 21:57:38 -04:00
josh 94f808b1fc user guide: add Barriers section 2019-07-29 21:32:04 -04:00
josh 51a9dd365f add :check_libpath option to check_lib configuration method - #107 2019-07-29 21:00:52 -04:00
josh 6e590b62a6 add :check_cpppath option to check_c_header and check_cxx_header
configuration methods
add :check_d_import_path option to check_d_import configuration method - #107
2019-07-09 23:53:17 -04:00
josh 3aac190ad6 configure checks: compile instead of link when looking for C/C++ header files and D imports 2019-07-09 23:41:51 -04:00
josh d6b9487e65 user guide: document -F command-line flag 2019-07-09 23:06:45 -04:00
josh 66d2700faa clarify -F command-line option usage more 2019-07-09 23:06:45 -04:00
josh ba98af1424 default configure checks :fail option to false if :set_define is specified 2019-07-09 22:00:50 -04:00
josh cf4f80c9ae user guide: document first compiler found is used 2019-07-09 21:47:45 -04:00
josh d74785d579 Add v2.0.0 changes to CHANGELOG.md 2019-07-07 22:15:44 -04:00
josh 4fd822fb95 user guide: add warning when viewing markdown source file directly 2019-07-07 21:38:17 -04:00
josh b39fd80d8c user guide: add ./configure && make Appendix section 2019-07-07 21:29:30 -04:00
josh ef00c9f377 add link to github.io site from README.md 2019-07-02 22:39:33 -04:00
69 changed files with 1755 additions and 485 deletions

No files matched your search

+78
View File
@@ -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
+14
View File
@@ -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
+10 -6
View File
@@ -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"
gem "yard" if RbConfig::CONFIG["host"]["msys"]
gem "rdoc" gem "json", "2.1.0"
gem "redcarpet" else
gem "syntax" gem "json"
gem "yard"
gem "rdoc"
gem "redcarpet"
gem "syntax"
end
+21 -21
View File
@@ -1,32 +1,32 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
diff-lcs (1.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
+4
View File
@@ -1,6 +1,10 @@
# Rscons # Rscons
![rscons logo](img/rscons_logo_1000.png)
Rscons (https://github.com/holtrop/rscons) is an open-source build system Rscons (https://github.com/holtrop/rscons) is an open-source build system
for developers. for developers.
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.
+25 -10
View File
@@ -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
task :user_guide do unless RbConfig::CONFIG["host"]["msys"]
system("ruby", "-Ilib", "rb/gen_user_guide.rb") require "yard"
YARD::Rake::YardocTask.new do |yard|
yard.files = ['lib/**/*.rb']
yard.options = ["-ogen/yard"]
end
desc "Build user guide"
task :user_guide do
system("ruby", "-Ilib", "rb/gen_user_guide.rb")
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
+5
View File
@@ -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
+4
View File
@@ -0,0 +1,4 @@
int two(void)
{
return 42;
}
+3 -2
View File
@@ -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
+3 -2
View File
@@ -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",
[], [],
+3 -2
View File
@@ -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",
[], [],
+4
View File
@@ -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"))
+9
View File
@@ -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
+1
View File
@@ -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
+6
View File
@@ -0,0 +1,6 @@
#include <stdio.h>
void foo(void)
{
printf("foo\n");
}
+12
View File
@@ -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 -1
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
echo "foobar!"
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
exit 42
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
echo "flex!"
+10
View File
@@ -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
+10
View File
@@ -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
+10
View File
@@ -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
+9
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
build do
puts "second build"
end
+7
View File
@@ -0,0 +1,7 @@
configure do
puts "sub Rsconscript configure"
end
build do
puts "sub Rsconscript build"
end
+7
View File
@@ -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 -2
View File
@@ -2,9 +2,9 @@ build do
Environment.new(echo: :command) do |env| Environment.new(echo: :command) do |env|
env.append('CPPPATH' => glob('src/**/*/')) env.append('CPPPATH' => glob('src/**/*/'))
env.add_build_hook do |builder| env.add_build_hook do |builder|
if File.basename(builder.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
View File
@@ -8,7 +8,7 @@ It supports the following features:
* built-in builders for several common operations * built-in builders for several common operations
* out-of-the-box support for C, C++, and D languages * out-of-the-box support for C, C++, and D languages
* extensibility for other languages or custom builders * extensibility for other languages or custom builders
* compatible with Windows, Linux, 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
View File
@@ -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
View File
@@ -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?
+9 -3
View File
@@ -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)
+3 -2
View File
@@ -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)
+1
View File
@@ -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)
+1 -1
View File
@@ -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
+4 -3
View File
@@ -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)
+1 -1
View File
@@ -23,7 +23,7 @@ module Rscons
@vars["_PREPROCESS_DEPGEN"] = depgen @vars["_PREPROCESS_DEPGEN"] = depgen
@vars["_TARGET"] = @target @vars["_TARGET"] = @target
@vars["_SOURCES"] = @sources @vars["_SOURCES"] = @sources
@vars["_DEPFILE"] = 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)
+2
View File
@@ -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])
+2
View File
@@ -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)
+2
View File
@@ -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
View File
@@ -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
+250 -157
View File
@@ -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
_, _, status = log_and_test_command(command) check_cpppath.each do |cpppath|
common_config_checks(status, options) env = BasicEnvironment.new
if cpppath
env["CPPPATH"] += Array(cpppath)
end
command = env.build_command("${CCCMD}", vars)
_, _, status = log_and_test_command(command)
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
_, _, status = log_and_test_command(command) check_cpppath.each do |cpppath|
common_config_checks(status, options) env = BasicEnvironment.new
if cpppath
env["CPPPATH"] += Array(cpppath)
end
command = env.build_command("${CXXCMD}", vars)
_, _, status = log_and_test_command(command)
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
_, _, status = log_and_test_command(command) check_d_import_path.each do |d_import_path|
common_config_checks(status, options) 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)
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
_, _, status = log_and_test_command(command) 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)
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 -1
View File
@@ -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.
+9 -10
View File
@@ -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
View File
@@ -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]
+61 -17
View File
@@ -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,21 +233,26 @@ 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
executable = executable.downcase if File.directory?(path_entry)
dir_entries = Dir.entries(path_entry) executable = executable.downcase
dir_entries.find do |entry| dir_entries = Dir.entries(path_entry)
path = "#{path_entry}/#{entry}" dir_entries.find do |entry|
entry = entry.downcase path = "#{path_entry}/#{entry}"
if ((entry == executable) or entry = entry.downcase
(entry == "#{executable}.exe") or if ((entry == executable) or
(entry == "#{executable}.com") or (entry == "#{executable}.exe") or
(entry == "#{executable}.bat")) and is_executable[path] (entry == "#{executable}.com") or
return path (entry == "#{executable}.bat")) and is_executable[path]
return path
end
end end
end end
else else
+1 -1
View File
@@ -1,4 +1,4 @@
module Rscons module Rscons
# Project version. # Project version.
VERSION = "2.0.0beta1" VERSION = "2.3.0"
end end
+6 -1
View File
@@ -1,6 +1,6 @@
<html> <html>
<head> <head>
<title>RScons User Guide<%= subpage_title %> - Version <%= Rscons::VERSION %></title> <title>Rscons User Guide<%= subpage_title %> - Version <%= Rscons::VERSION %></title>
<style> <style>
body { body {
background-color: #CCC; background-color: #CCC;
@@ -31,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
View File
@@ -44,7 +44,7 @@ combine_files[START_FILE]
# Strip Ruby comment lines and empty lines to save some space, but do not # Strip Ruby comment lines and empty lines to save some space, but do not
# remove lines that are in heredoc sections. This isn't terribly robust to be # remove lines that are in heredoc sections. This isn't terribly robust to be
# used in the wild, but works for the heredoc instances for this project. # used in the wild, but works for the heredoc instances for this project.
stripped_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
View File
@@ -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)
+520 -146
View File
File diff suppressed because it is too large. Load diff
+21 -5
View File
@@ -68,7 +68,7 @@ EOF
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("mingw") expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("mingw")
end end
it "returns the number of logical processors that wmic reports" do it "returns the number of logical processors that wmic reports" do
expect(Util).to receive(:`).with("wmic cpu get NumberOfLogicalProcessors /value").and_return("NumberOfLogicalProcessors=7") expect(Util).to receive(:`).with("wmic cpu get NumberOfLogicalProcessors -value").and_return("NumberOfLogicalProcessors=7")
expect(Util.determine_n_threads).to eq(7) expect(Util.determine_n_threads).to eq(7)
end end
end end
@@ -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
-10
View File
@@ -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)
+20 -20
View File
@@ -1,25 +1,25 @@
require "simplecov"
SimpleCov.start do
add_filter "/spec/"
add_filter "/.bundle/"
if ENV["partial_specs"]
command_name "RSpec-partial"
else
command_name "RSpec"
end
if ENV["dist_specs"]
add_filter "/bin/"
add_filter "/lib/"
else
add_filter "test/rscons.rb"
end
project_name "Rscons"
merge_timeout 3600
end
if ENV["dist_specs"] if ENV["dist_specs"]
require_relative "../test/rscons" require_relative "../test/rscons"
else else
require "simplecov"
SimpleCov.start do
add_filter "/spec/"
add_filter "/.bundle/"
if ENV["partial_specs"]
command_name "RSpec-partial"
else
command_name "RSpec"
end
if ENV["dist_specs"]
add_filter "/bin/"
add_filter "/lib/"
else
add_filter "test/rscons.rb"
end
project_name "Rscons"
merge_timeout 3600
end
require "rscons" require "rscons"
end end