Compare commits
1
Commits
v2.0.1
..
784bbd471b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
784bbd471b |
No files matched your search
+1
-3
@@ -4,8 +4,6 @@
|
|||||||
/build_test_run/
|
/build_test_run/
|
||||||
/coverage/
|
/coverage/
|
||||||
/dist/
|
/dist/
|
||||||
/gen/
|
/doc/
|
||||||
/large_project/
|
|
||||||
/pkg/
|
/pkg/
|
||||||
/test/
|
/test/
|
||||||
/yard/
|
|
||||||
+70
-104
@@ -1,114 +1,80 @@
|
|||||||
## v2.0.0
|
## ChangeLog
|
||||||
|
|
||||||
- convert rscons from a Ruby gem to a standalone script
|
### v1.17.0
|
||||||
- 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
|
#### New Features
|
||||||
|
|
||||||
### New Features
|
|
||||||
|
|
||||||
- allow construction variable expansion on `true` and `false` values.
|
- allow construction variable expansion on `true` and `false` values.
|
||||||
- remove makefile target name check when parsing dependencies
|
- remove makefile target name check when parsing dependencies
|
||||||
|
|
||||||
## v1.16.0
|
### v1.16.0
|
||||||
|
|
||||||
### New Features
|
#### New Features
|
||||||
|
|
||||||
- Add `Rscons.glob`
|
- Add `Rscons.glob`
|
||||||
- Support command-line variables
|
- Support command-line variables
|
||||||
- improve debuggability of `cache.up_to_date?`
|
- improve debuggability of cache.up_to_date?
|
||||||
- allow passing a VarSet into cache methods
|
- allow passing a VarSet into cache methods
|
||||||
|
|
||||||
### Fixes
|
#### Fixes
|
||||||
|
|
||||||
- generate dependencies for D builds
|
- generate dependencies for D builds
|
||||||
|
|
||||||
## v1.15.0
|
### v1.15.0
|
||||||
|
|
||||||
- allow json 1.x or 2.x
|
- allow json 1.x or 2.x
|
||||||
|
|
||||||
## v1.14.0
|
### v1.14.0
|
||||||
|
|
||||||
### New Features
|
#### New Features
|
||||||
|
|
||||||
- #45 - Add `Rscons::VarSet#values_at`
|
- #45 - Add Rscons::VarSet#values_at
|
||||||
|
|
||||||
### Fixes
|
#### Fixes
|
||||||
|
|
||||||
- #44 - `Environment#print_builder_run_message` should support string commands
|
- #44 - Environment#print_builder_run_message should support string commands
|
||||||
|
|
||||||
## v1.13.0
|
### v1.13.0
|
||||||
|
|
||||||
### New Features
|
#### New Features
|
||||||
|
|
||||||
- #43 - Add ability to record side-effect file production
|
- #43 - Add ability to record side-effect file production
|
||||||
|
|
||||||
## v1.12.0
|
### v1.12.0
|
||||||
|
|
||||||
### New Features
|
#### New Features
|
||||||
|
|
||||||
- #40 - env.depends should imply `env.build_after`
|
- #40 - env.depends should imply env.build_after
|
||||||
- #41 - be more colorful
|
- #41 - be more colorful
|
||||||
|
|
||||||
### Fixes
|
#### Fixes
|
||||||
|
|
||||||
- #39 - wait for in-progress subcommands to complete on build failure
|
- #39 - wait for in-progress subcommands to complete on build failure
|
||||||
- #42 - cloned Environments should inherit `n_threads`
|
- #42 - cloned Environments should inherit n_threads
|
||||||
|
|
||||||
## v1.11.1
|
### v1.11.1
|
||||||
|
|
||||||
### Fixes
|
#### Fixes
|
||||||
|
|
||||||
- fix the circular build dependency detection logic
|
- fix the circular build dependency detection logic
|
||||||
|
|
||||||
## v1.11.0
|
### v1.11.0
|
||||||
|
|
||||||
### New Features
|
#### New Features
|
||||||
|
|
||||||
- Change default Environment :clone option to :all to clone all attributes
|
- Change default Environment :clone option to :all to clone all attributes
|
||||||
- #38 - raise error when circular dependencies are found
|
- #38 - raise error when circular dependencies are found
|
||||||
- #34 - Allow overriding `n_threads` on a per-Environment level
|
- #34 - Allow overriding n_threads on a per-Environment level
|
||||||
|
|
||||||
### Fixes
|
#### Fixes
|
||||||
|
|
||||||
- #35 - `env.build_after` should expand paths
|
- #35 - env.build_after should expand paths
|
||||||
- #36 - `SHCFLAGS` and `SHCXXFLAGS` should inherit non-SH flags by default
|
- #36 - SHCFLAGS and SHCXXFLAGS should inherit non-SH flags by default
|
||||||
- #37 - Fix non-blocking thread-wait if `Rscons.n_threads` is set to 0
|
- #37 - Fix non-blocking thread-wait if Rscons.n_threads is set to 0
|
||||||
|
|
||||||
## v1.10.0
|
### v1.10.0
|
||||||
|
|
||||||
### New Features
|
#### New Features
|
||||||
|
|
||||||
- #23 - add parallelization - builds are now parallelized by default
|
- #23 - add parallelization - builds are now parallelized by default
|
||||||
- #31 - add LEXSUFFIX, YACCSUFFIX construction variables
|
- #31 - add LEXSUFFIX, YACCSUFFIX construction variables
|
||||||
@@ -118,100 +84,100 @@
|
|||||||
- Add builder features
|
- Add builder features
|
||||||
- #8 - add SharedObject and SharedLibrary builders
|
- #8 - add SharedObject and SharedLibrary builders
|
||||||
|
|
||||||
### Fixes
|
#### Fixes
|
||||||
|
|
||||||
- expand target and source paths before calling `Builder#create_build_target`
|
- expand target and source paths before calling Builder#create_build_target
|
||||||
- #29 - fix `PROGSUFFIX` handling
|
- #29 - fix PROGSUFFIX handling
|
||||||
- #32 - Pre-build hooks do not respect modified key values
|
- #32 - Pre-build hooks do not respect modified key values
|
||||||
|
|
||||||
## v1.9.3
|
### v1.9.3
|
||||||
|
|
||||||
- `Environment#parse_flags` should put -std=XXX flags in CCFLAGS, not CFLAGS
|
- Environment#parse_flags should put -std=XXX flags in CCFLAGS, not CFLAGS
|
||||||
|
|
||||||
## v1.9.2
|
### v1.9.2
|
||||||
|
|
||||||
- allow phony targets in conjunction with build roots
|
- allow phony targets in conjunction with build roots
|
||||||
|
|
||||||
## v1.9.1
|
### v1.9.1
|
||||||
|
|
||||||
- change *SUFFIX defaults to arrays
|
- change *SUFFIX defaults to arrays
|
||||||
- add various C++ file suffixes
|
- add various C++ file suffixes
|
||||||
- use ${INCPREFIX} instead of hard-coded "-I" in Preprocess builder
|
- use ${INCPREFIX} instead of hard-coded "-I" in Preprocess builder
|
||||||
|
|
||||||
## v1.9.0
|
### v1.9.0
|
||||||
|
|
||||||
### New Features
|
#### New Features
|
||||||
|
|
||||||
- #6 - add Install and Copy builders
|
- #6 - add Install and Copy builders
|
||||||
- #22 - allow overriding Command builder short description with `CMD_DESC` variable
|
- #22 - allow overriding Command builder short description with CMD_DESC variable
|
||||||
- #24 - add "rscons" executable
|
- #24 - add "rscons" executable
|
||||||
- #25 - add support for phony targets given as Symbols instead of Strings
|
- #25 - add support for phony targets given as Symbols instead of Strings
|
||||||
- #26 - support registering multiple build targets with the same target name
|
- #26 - support registering multiple build targets with the same target name
|
||||||
- #27 - add Directory builder
|
- #27 - add Directory builder
|
||||||
|
|
||||||
### Fixes
|
#### Fixes
|
||||||
|
|
||||||
- #20 - fix variable references that expand to arrays in build target sources
|
- #20 - fix variable references that expand to arrays in build target sources
|
||||||
- #21 - rework Preprocess builder to consider deep dependencies
|
- #21 - rework Preprocess builder to consider deep dependencies
|
||||||
- fix `Rscons.set_suffix` to append the given suffix if the filename has none
|
- fix Rscons.set_suffix to append the given suffix if the filename has none
|
||||||
- remove ${CFLAGS} from default `CPP_CMD`
|
- remove ${CFLAGS} from default CPP_CMD
|
||||||
|
|
||||||
## v1.8.1
|
### v1.8.1
|
||||||
|
|
||||||
- fix Environment#dump when construction variables are symbols
|
- fix Environment#dump when construction variables are symbols
|
||||||
|
|
||||||
## v1.8.0
|
### v1.8.0
|
||||||
|
|
||||||
- new Command builder to execute arbitrary user commands
|
- new Command builder to execute arbitrary user commands
|
||||||
- new SimpleBuilder class
|
- new SimpleBuilder class
|
||||||
- create new builders quickly by passing a block to `Environment#add_builder`
|
- create new builders quickly by passing a block to Environment#add_builder
|
||||||
- improved YARD documentation
|
- improved YARD documentation
|
||||||
- add Environment#dump to debug Environment construction variables
|
- add Environment#dump to debug Environment construction variables
|
||||||
|
|
||||||
## v1.7.0
|
### v1.7.0
|
||||||
|
|
||||||
- allow build hooks to register new build targets
|
- allow build hooks to register new build targets
|
||||||
- add post-build hooks (register with `Environment#add_post_build_hook`)
|
- add post-build hooks (register with Environment#add_post_build_hook)
|
||||||
- clear all build targets after processing an Environment
|
- clear all build targets after processing an Environment
|
||||||
- allow trailing slashes in arguments to `Environment#build_dir`
|
- allow trailing slashes in arguments to Environment#build_dir
|
||||||
|
|
||||||
## v1.6.1
|
### v1.6.1
|
||||||
|
|
||||||
- add DEPFILESUFFIX construction variable to override dependency file suffix
|
- add DEPFILESUFFIX construction variable to override dependency file suffix
|
||||||
- fix Environment#depends to expand its arguments for construction variables
|
- fix Environment#depends to expand its arguments for construction variables
|
||||||
|
|
||||||
## v1.6.0
|
### v1.6.0
|
||||||
|
|
||||||
- support lambdas as construction variable values
|
- support lambdas as construction variable values
|
||||||
|
|
||||||
## v1.5.0
|
### v1.5.0
|
||||||
|
|
||||||
- add "json" as a runtime dependency
|
- add "json" as a runtime dependency
|
||||||
- update construction variables to match SCons more closely
|
- update construction variables to match SCons more closely
|
||||||
- add `CPPDEFPREFIX`, `INCPREFIX`, `CPPDEFINES`, `CCFLAGS`, `LIBDIRPREFIX`, and `LIBLINKPREFIX`
|
- add CPPDEFPREFIX, INCPREFIX, CPPDEFINES, CCFLAGS, LIBDIRPREFIX, and LIBLINKPREFIX
|
||||||
- add `Environment#shell`
|
- add Environment#shell
|
||||||
- add `Environment#parse_flags`, `#parse_flags!`, `#merge_flags`
|
- add Environment#parse_flags, #parse_flags!, #merge_flags
|
||||||
- unbuffer `$stdout` by default
|
- unbuffer $stdout by default
|
||||||
- add `PROGSUFFIX` construction variable (defaults to `.exe` on MinGW/Cygwin)
|
- add PROGSUFFIX construction variable (defaults to .exe on MinGW/Cygwin)
|
||||||
- add `Rscons::BuildTarget` and `Builder#create_build_target`
|
- add Rscons::BuildTarget and Builder#create_build_target
|
||||||
- update specs to RSpec 3.x and fix to run on MinGW/Cygwin/Linux
|
- update specs to RSpec 3.x and fix to run on MinGW/Cygwin/Linux
|
||||||
- add YARD documentation to get to 100% coverage
|
- add YARD documentation to get to 100% coverage
|
||||||
|
|
||||||
## v1.4.3
|
### v1.4.3
|
||||||
|
|
||||||
- fix builders properly using construction variable overrides
|
- fix builders properly using construction variable overrides
|
||||||
- expand nil construction variables to empty strings
|
- expand nil construction variables to empty strings
|
||||||
|
|
||||||
## v1.4.2
|
### v1.4.2
|
||||||
|
|
||||||
- add `Environment#expand_path`
|
- add Environment#expand_path
|
||||||
- expand construction variable references in builder targets and sources before invoking builder
|
- expand construction variable references in builder targets and sources before invoking builder
|
||||||
|
|
||||||
## v1.4.1
|
### v1.4.1
|
||||||
|
|
||||||
- fix invoking a builder with no sources while a build root defined
|
- fix invoking a builder with no sources while a build root defined
|
||||||
|
|
||||||
## v1.4.0
|
### v1.4.0
|
||||||
|
|
||||||
- add CFile builder
|
- add CFile builder
|
||||||
- add Disassemble builder
|
- add Disassemble builder
|
||||||
@@ -224,21 +190,21 @@
|
|||||||
- implement copy-on-write semantics for construction variables when cloning Environments
|
- implement copy-on-write semantics for construction variables when cloning Environments
|
||||||
- only load the cache once instead of on each Environment#process
|
- only load the cache once instead of on each Environment#process
|
||||||
- only write the cache when something has changed
|
- only write the cache when something has changed
|
||||||
- fix `Cache#mkdir_p` to handle relative paths (Issue #5)
|
- fix Cache#mkdir_p to handle relative paths (Issue #5)
|
||||||
- flush the cache to disk if a builder raises an exception (Issue #4)
|
- flush the cache to disk if a builder raises an exception (Issue #4)
|
||||||
|
|
||||||
## v1.3.0
|
### v1.3.0
|
||||||
|
|
||||||
- change Environment#execute() options parameter to accept the following options keys:
|
- change Environment#execute() options parameter to accept the following options keys:
|
||||||
- :env to pass an environment Hash to Kernel#system
|
- :env to pass an environment Hash to Kernel#system
|
||||||
- :options to pass an options Hash to Kernel#system
|
- :options to pass an options Hash to Kernel#system
|
||||||
|
|
||||||
## v1.2.0
|
### v1.2.0
|
||||||
|
|
||||||
- add :clone option to Environment#clone to control exactly which Environment attributes are cloned
|
- add :clone option to Environment#clone to control exactly which Environment attributes are cloned
|
||||||
- allow nil to be passed in to `Environment#build_root=`
|
- allow nil to be passed in to Environment#build_root=
|
||||||
|
|
||||||
## v1.1.0
|
### v1.1.0
|
||||||
|
|
||||||
- Change `Cache#up_to_date?` and `#register_build` to accept a single target
|
- Change Cache#up_to_date?() and #register_build() to accept a single target
|
||||||
file or an array of target file names
|
file or an array of target file names
|
||||||
@@ -6,5 +6,3 @@ gem "rake"
|
|||||||
gem "simplecov"
|
gem "simplecov"
|
||||||
gem "yard"
|
gem "yard"
|
||||||
gem "rdoc"
|
gem "rdoc"
|
||||||
gem "redcarpet"
|
|
||||||
gem "syntax"
|
|
||||||
+17
-21
@@ -2,31 +2,29 @@ GEM
|
|||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
diff-lcs (1.3)
|
diff-lcs (1.3)
|
||||||
docile (1.3.2)
|
docile (1.1.5)
|
||||||
json (2.2.0)
|
json (2.1.0)
|
||||||
rake (12.3.2)
|
rake (12.3.1)
|
||||||
rdoc (6.1.1)
|
rdoc (5.1.0)
|
||||||
redcarpet (3.4.0)
|
rspec (3.6.0)
|
||||||
rspec (3.8.0)
|
rspec-core (~> 3.6.0)
|
||||||
rspec-core (~> 3.8.0)
|
rspec-expectations (~> 3.6.0)
|
||||||
rspec-expectations (~> 3.8.0)
|
rspec-mocks (~> 3.6.0)
|
||||||
rspec-mocks (~> 3.8.0)
|
rspec-core (3.6.0)
|
||||||
rspec-core (3.8.2)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-expectations (3.6.0)
|
||||||
rspec-expectations (3.8.4)
|
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-mocks (3.8.1)
|
rspec-mocks (3.6.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-support (3.8.2)
|
rspec-support (3.6.0)
|
||||||
simplecov (0.15.0)
|
simplecov (0.15.0)
|
||||||
docile (~> 1.1.0)
|
docile (~> 1.1.0)
|
||||||
json (>= 1.8, < 3)
|
json (>= 1.8, < 3)
|
||||||
simplecov-html (~> 0.10.0)
|
simplecov-html (~> 0.10.0)
|
||||||
simplecov-html (0.10.2)
|
simplecov-html (0.10.2)
|
||||||
syntax (1.2.2)
|
yard (0.9.12)
|
||||||
yard (0.9.20)
|
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
@@ -36,11 +34,9 @@ DEPENDENCIES
|
|||||||
json
|
json
|
||||||
rake
|
rake
|
||||||
rdoc
|
rdoc
|
||||||
redcarpet
|
|
||||||
rspec
|
rspec
|
||||||
simplecov
|
simplecov
|
||||||
syntax
|
|
||||||
yard
|
yard
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.17.3
|
1.16.2
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2013-2019 Josh Holtrop
|
Copyright (c) 2013 Josh Holtrop
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,591 @@
|
|||||||
# Rscons
|
# Rscons
|
||||||
|
|
||||||

|
Rscons (https://github.com/holtrop/rscons) is a software construction framework
|
||||||
|
inspired by SCons and waf but implemented in Ruby.
|
||||||
|
|
||||||
Rscons (https://github.com/holtrop/rscons) is an open-source build system
|
## Installation
|
||||||
for developers.
|
|
||||||
|
|
||||||
Rscons is written in Ruby, and is inspired by [SCons](https://scons.org/) and [waf](https://waf.io/).
|
Rscons is distributed as a standalone Ruby script named ``rscons``. This file
|
||||||
|
(containing the complete rscons build system) can be checked into your project
|
||||||
|
and versioned along with your project.
|
||||||
|
|
||||||
See [https://holtrop.github.io/rscons/index.html](https://holtrop.github.io/rscons/index.html) for User Guide and Installation instructions.
|
## Usage
|
||||||
|
|
||||||
|
### Standalone
|
||||||
|
|
||||||
|
Rscons provides a standalone executable ("rscons") with a command-line
|
||||||
|
interface. The rscons executable will read a build script (by default named
|
||||||
|
Rsconsfile or Rsconsfile.rb) and execute its contents.
|
||||||
|
|
||||||
|
### With Rake
|
||||||
|
|
||||||
|
Rscons can be used with rake as well. The same content that would be written
|
||||||
|
in Rsconsfile can be placed in a Rakefile. It could be placed within a rake
|
||||||
|
task block or split among multiple tasks.
|
||||||
|
|
||||||
|
## Example Build Scripts
|
||||||
|
|
||||||
|
### Example: Building a C Program
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env["CFLAGS"] << "-Wall"
|
||||||
|
env.Program("program", Rscons.glob("src/**/*.c"))
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Building a D Program
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env["DFLAGS"] << "-Wall"
|
||||||
|
env.Program("program", Rscons.glob("src/**/*.d"))
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Cloning an Environment
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
main_env = Rscons::Environment.new do |env|
|
||||||
|
# Store object files from sources under "src" in "build/main"
|
||||||
|
env.build_dir("src", "build/main")
|
||||||
|
env["CFLAGS"] = ["-DSOME_DEFINE", "-O3"]
|
||||||
|
env["LIBS"] = ["SDL"]
|
||||||
|
env.Program("program", Rscons.glob("src/**/*.cc"))
|
||||||
|
end
|
||||||
|
|
||||||
|
debug_env = main_env.clone do |env|
|
||||||
|
# Store object files from sources under "src" in "build/debug"
|
||||||
|
env.build_dir("src", "build/debug")
|
||||||
|
env["CFLAGS"] -= ["-O3"]
|
||||||
|
env["CFLAGS"] += ["-g", "-O0"]
|
||||||
|
env.Program("program-debug", Rscons.glob("src/**/*.cc"))
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Custom Builder
|
||||||
|
|
||||||
|
Custom builders are implemented as classes which extend from `Rscons::Builder`.
|
||||||
|
The builder must have a `run` method which is called to invoke the builder.
|
||||||
|
The `run` method should return the name of the target built on success, and
|
||||||
|
`false` on failure.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
class GenerateFoo < Rscons::Builder
|
||||||
|
def run(target, sources, cache, env, vars)
|
||||||
|
cache.mkdir_p(File.dirname(target))
|
||||||
|
File.open(target, "w") do |fh|
|
||||||
|
fh.puts <<EOF
|
||||||
|
#define GENERATED 42
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
target
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env.add_builder(GenerateFoo.new)
|
||||||
|
env.GenerateFoo("foo.h", [])
|
||||||
|
env.Program("a.out", Rscons.glob("*.c"))
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Custom Builder That Only Regenerates When Necessary
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
class CmdBuilder < Rscons::Builder
|
||||||
|
def run(target, sources, cache, env, vars)
|
||||||
|
cmd = ["cmd", "-i", sources.first, "-o", target]
|
||||||
|
unless cache.up_to_date?(target, cmd, sources, env)
|
||||||
|
cache.mkdir_p(File.dirname(target))
|
||||||
|
system(cmd)
|
||||||
|
cache.register_build(target, cmd, sources, env)
|
||||||
|
end
|
||||||
|
target
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env.add_builder(CmdBuilder.new)
|
||||||
|
env.CmdBuilder("foo.gen", "foo_gen.cfg")
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Cache#up_to_date?` method accepts an optional 5th parameter which is an
|
||||||
|
options Hash. The `:debug` option can be specified in this Hash with a value
|
||||||
|
of `true` to aid in debugging builders while developing them. For example:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
unless cache.up_to_date?(target, cmd, sources, env, debug: true)
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Custom Builder That Generates Multiple Output Files
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
class CModuleGenerator < Rscons::Builder
|
||||||
|
def run(target, sources, cache, env, vars)
|
||||||
|
c_fname = target
|
||||||
|
h_fname = target.sub(/\.c$/, ".h")
|
||||||
|
cmd = ["generate_c_and_h", sources.first, c_fname, h_fname]
|
||||||
|
unless cache.up_to_date?([c_fname, h_fname], cmd, sources, env)
|
||||||
|
cache.mkdir_p(File.dirname(target))
|
||||||
|
system(cmd)
|
||||||
|
cache.register_build([c_fname, h_fname], cmd, sources, env)
|
||||||
|
end
|
||||||
|
target
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env.add_builder(CModuleGenerator.new)
|
||||||
|
env.CModuleGenerator("build/foo.c", "foo_gen.cfg")
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Custom Builder Using Builder#standard_build()
|
||||||
|
|
||||||
|
The `standard_build` method from the `Rscons::Builder` base class can be used
|
||||||
|
when the builder needs to execute a system command to produce the target file.
|
||||||
|
The `standard_build` method will return the correct value so its return value
|
||||||
|
can be used as the return value from the `run` method.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
class CmdBuilder < Rscons::Builder
|
||||||
|
def run(target, sources, cache, env, vars)
|
||||||
|
cmd = ["cmd", "-i", sources.first, "-o", target]
|
||||||
|
standard_build("CmdBld #{target}", target, cmd, sources, env, cache)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env.add_builder(CmdBuilder.new)
|
||||||
|
env.CmdBuilder("foo.gen", "foo_gen.cfg")
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Custom Builder Using Environment#add_builder()
|
||||||
|
|
||||||
|
The `add_builder` method of the `Rscons::Environment` class optionally allows
|
||||||
|
you to define and register a builder by providing a name and action block. This
|
||||||
|
can be useful if the builder you are trying to define is easily expressed as a
|
||||||
|
short ruby procedure. When `add_builder` is called in this manner a new builder
|
||||||
|
will be registered with the environment with the given name. When this builder
|
||||||
|
is used it will call the provided block in order to build the target.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env.add_builder(:JsonToYaml) do |target, sources, cache, env, vars|
|
||||||
|
unless cache.up_to_date?(target, :JsonToYaml, sources, env)
|
||||||
|
cache.mkdir_p(File.dirname(target))
|
||||||
|
File.open(target, 'w') do |f|
|
||||||
|
f.write(YAML.dump(JSON.load(IO.read(sources.first))))
|
||||||
|
end
|
||||||
|
cache.register_build(target, :JsonToYaml, sources, env)
|
||||||
|
end
|
||||||
|
target
|
||||||
|
end
|
||||||
|
env.JsonToYaml('foo.yml','foo.json')
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Using different compilation flags for some sources
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env["CFLAGS"] = ["-O3", "-Wall", "-DDEFINE"]
|
||||||
|
env.add_build_hook do |build_op|
|
||||||
|
if build_op[:target] =~ %r{build/third-party}
|
||||||
|
build_op[:vars]["CFLAGS"] -= ["-Wall"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
env.build_dir("src", "build")
|
||||||
|
env.Program("program", Rscons.glob("**/*.cc"))
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Creating a static library
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env.Library("mylib.a", Rscons.glob("src/**/*.c"))
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Creating a C++ parser source from a Yacc/Bison input file
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env.CFile("#{env.build_root}/parser.tab.cc", "parser.yy")
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
### Environments
|
||||||
|
|
||||||
|
The Environment is the main top-level object that Rscons operates with. An
|
||||||
|
Environment must be created by the user in order to build anything. All build
|
||||||
|
targets are registered within an Environment. In many cases only a single
|
||||||
|
Environment will be needed, but more than one can be created (either from
|
||||||
|
scratch or by cloning another existing Environment) if needed.
|
||||||
|
|
||||||
|
An Environment consists of:
|
||||||
|
|
||||||
|
* a collection of builders
|
||||||
|
* a collection of construction variables used by those builders
|
||||||
|
* a mapping of build directories from source directories
|
||||||
|
* a default build root to apply if no specific build directories are matched
|
||||||
|
* a collection of user-defined build targets
|
||||||
|
* a collection of user-defined build hooks
|
||||||
|
|
||||||
|
When cloning an environment, by default the construction variables, builders,
|
||||||
|
build hooks, build directories, and build root are cloned, but the new
|
||||||
|
environment does not inherit any of the registered build targets.
|
||||||
|
|
||||||
|
The set of environment attributes that are cloned is controllable via the
|
||||||
|
`:clone` option to the `#clone` method.
|
||||||
|
For example, `env.clone(clone: [:variables, :builders])` will include
|
||||||
|
construction variables, and builders but not build hooks, build directories, or
|
||||||
|
the build root.
|
||||||
|
|
||||||
|
The set of pending targets is never cloned.
|
||||||
|
|
||||||
|
Cloned environments contain "deep copies" of construction variables.
|
||||||
|
For example, in:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
base_env = Rscons::Environment.new
|
||||||
|
base_env["CPPPATH"] = ["one", "two"]
|
||||||
|
cloned_env = base_env.clone
|
||||||
|
cloned_env["CPPPATH"] << "three"
|
||||||
|
```
|
||||||
|
|
||||||
|
`base_env["CPPPATH"]` will not include "three".
|
||||||
|
|
||||||
|
### Builders
|
||||||
|
|
||||||
|
Builders are the workhorses that Rscons uses to execute build operations.
|
||||||
|
Each builder is specialized to perform a particular operation.
|
||||||
|
|
||||||
|
Rscons ships with a number of builders:
|
||||||
|
|
||||||
|
* Command, which executes a user-defined command to produce the target.
|
||||||
|
* Copy, which is identical to Install.
|
||||||
|
* CFile, which builds a C or C++ source file from a lex or yacc input file.
|
||||||
|
* Disassemble, which disassembles an object file to a disassembly listing.
|
||||||
|
* Install, which installs files or directories to a specified destination.
|
||||||
|
* Library, which collects object files into a static library archive file.
|
||||||
|
* Object, which compiles source files to produce an object file.
|
||||||
|
* Preprocess, which invokes the C/C++ preprocessor on a source file.
|
||||||
|
* Program, which links object files to produce an executable.
|
||||||
|
* SharedLibrary, which links object files to produce a dynamically loadable
|
||||||
|
library.
|
||||||
|
* SharedObject, which compiles source files to produce an object file, in a way
|
||||||
|
that is able to be used to create a shared library.
|
||||||
|
|
||||||
|
If you want to create an Environment that does not contain any builders,
|
||||||
|
you can use the `:exclude_builders` key to the Environment constructor.
|
||||||
|
|
||||||
|
#### Command
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.Command(target, sources, "CMD" => command)
|
||||||
|
# Example
|
||||||
|
env.Command("docs.html", "docs.md",
|
||||||
|
"CMD" => ["pandoc", "-fmarkdown", "-thtml", "-o${_TARGET}", "${_SOURCES}"],
|
||||||
|
"CMD_DESC" => "PANDOC")
|
||||||
|
```
|
||||||
|
|
||||||
|
The command builder executes a user-defined command in order to produce the
|
||||||
|
desired target file based on the provided source files.
|
||||||
|
|
||||||
|
#### CFile
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.CFile(target, source)
|
||||||
|
# Example
|
||||||
|
env.CFile("parser.c", "parser.y")
|
||||||
|
```
|
||||||
|
|
||||||
|
The CFile builder will generate a C or C++ source file from a lex (.l, .ll)
|
||||||
|
or yacc (.y, .yy) input file.
|
||||||
|
|
||||||
|
#### Disassemble
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.Disassemble(target, source)
|
||||||
|
# Example
|
||||||
|
env.Disassemble("module.dis", "module.o")
|
||||||
|
```
|
||||||
|
|
||||||
|
The Disassemble builder generates a disassembly listing using objdump from
|
||||||
|
and object file.
|
||||||
|
|
||||||
|
#### Install
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.Install(destination, sources)
|
||||||
|
# Example
|
||||||
|
env.Install("dist/bin", "app.exe")
|
||||||
|
env.Install("dist/share", "share")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Library
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.Library(target, sources)
|
||||||
|
# Example
|
||||||
|
env.Library("lib.a", Rscons.glob("src/**/*.c"))
|
||||||
|
```
|
||||||
|
|
||||||
|
The Library builder creates a static library archive from the given source
|
||||||
|
files.
|
||||||
|
|
||||||
|
#### Object
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.Object(target, sources)
|
||||||
|
# Example
|
||||||
|
env.Object("module.o", "module.c")
|
||||||
|
```
|
||||||
|
|
||||||
|
The Object builder compiles the given sources to an object file. Although it
|
||||||
|
can be called explicitly, it is more commonly implicitly called by the Program
|
||||||
|
builder.
|
||||||
|
|
||||||
|
#### Preprocess
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.Preprocess(target, source)
|
||||||
|
# Example
|
||||||
|
env.Preprocess("module-preprocessed.cc", "module.cc")
|
||||||
|
```
|
||||||
|
|
||||||
|
The Preprocess builder invokes either `${CC}` or `${CXX}` (depending on if the
|
||||||
|
source contains an extension in `${CXXSUFFIX}` or not) and writes the
|
||||||
|
preprocessed output to the target file.
|
||||||
|
|
||||||
|
#### Program
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.Program(target, sources)
|
||||||
|
# Example
|
||||||
|
env.Program("myprog", Rscons.glob("src/**/*.cc"))
|
||||||
|
```
|
||||||
|
|
||||||
|
The Program builder compiles and links the given sources to an executable file.
|
||||||
|
Object files or source files can be given as `sources`. A platform-dependent
|
||||||
|
program suffix will be appended to the target name if one is not specified.
|
||||||
|
This can be controlled with the `PROGSUFFIX` construction variable.
|
||||||
|
|
||||||
|
#### SharedLibrary
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.SharedLibrary(target, sources)
|
||||||
|
# Example
|
||||||
|
env.SharedLibrary("mydll", Rscons.glob("src/**/*.cc"))
|
||||||
|
```
|
||||||
|
|
||||||
|
The SharedLibrary builder compiles and links the given sources to a dynamically
|
||||||
|
loadable library. Object files or source files can be given as `sources`.
|
||||||
|
A platform-dependent prefix and suffix will be appended to the target name if
|
||||||
|
they are not specified by the user. These values can be controlled by
|
||||||
|
overriding the `SHLIBPREFIX` and `SHLIBSUFFIX` construction variables.
|
||||||
|
|
||||||
|
#### SharedObject
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.SharedObject(target, sources)
|
||||||
|
# Example
|
||||||
|
env.SharedObject("lib_module.o", "lib_module.c")
|
||||||
|
```
|
||||||
|
|
||||||
|
The SharedObject builder compiles the given sources to an object file. Any
|
||||||
|
compilation flags necessary to build the object file in a manner that 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 the SharedLibrary builder.
|
||||||
|
|
||||||
|
### Construction Variables
|
||||||
|
|
||||||
|
Construction variables are used to define the toolset and any build options
|
||||||
|
that Rscons will use to build a project. The default construction variable
|
||||||
|
values are configured to build applications using gcc. However, all
|
||||||
|
construction variables can be overridden by the user.
|
||||||
|
|
||||||
|
| Name | Type | Description | Default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| AR | String | Static library archiver executable | "ar" |
|
||||||
|
| ARCMD | Array | Static library archiver command line | ["${AR}", "${ARFLAGS}", "${_TARGET}", "${_SOURCES}"] |
|
||||||
|
| ARFLAGS | Array | Static library archiver flags | ["rcs"] |
|
||||||
|
| AS | String | Assembler executable | "${CC}" |
|
||||||
|
| ASCMD | Array | Assembler command line | ["${AS}", "-c", "-o", "${_TARGET}", "${ASDEPGEN}", "${INCPREFIX}${ASPPPATH}", "${ASPPFLAGS}", "${ASFLAGS}", "${_SOURCES}"] |
|
||||||
|
| ASDEPGEN | Array | Assembly dependency generation flags | ["-MMD", "-MF", "${_DEPFILE}", "-MT", "TARGET"] |
|
||||||
|
| ASFLAGS | Array | Assembler flags | [] |
|
||||||
|
| ASPPFLAGS | Array | Assembler preprocessor flags | ["${CPPFLAGS}"] |
|
||||||
|
| ASPPPATH | Array | Assembler preprocessor path | ["${CPPPATH}"] |
|
||||||
|
| ASSUFFIX | Array | Assembly file suffixes | [".S"] |
|
||||||
|
| CC | String | C compiler executable | "gcc" |
|
||||||
|
| CCCMD | Array | C compiler command line | ["${CC}", "-c", "-o", "${_TARGET}", "${CCDEPGEN}", "${INCPREFIX}${CPPPATH}", "${CPPFLAGS}", "${CFLAGS}", "${CCFLAGS}", "${_SOURCES}"] |
|
||||||
|
| CCDEPGEN | Array | C compiler dependency generation flags | ["-MMD", "-MF", "${_DEPFILE}", "-MT", "TARGET"] |
|
||||||
|
| CCFLAGS | Array | Common flags for both C and C++ compiler | [] |
|
||||||
|
| CFLAGS | Array | C compiler flags | [] |
|
||||||
|
| CPP_CMD | Array | Preprocess command line | ["${_PREPROCESS_CC}", "-E", "${_PREPROCESS_DEPGEN}", "-o", "${_TARGET}", "${INCPREFIX}${CPPPATH}", "${CPPFLAGS}", "${_SOURCES}"] |
|
||||||
|
| CPP_TARGET_SUFFIX | String | Suffix used for crt:preprocess target filename. | ".c" |
|
||||||
|
| CPPDEFINES | Array | C preprocessor defines | [] |
|
||||||
|
| CPPDEFPREFIX | String | Prefix used for C preprocessor to introduce a define | "-D" |
|
||||||
|
| CPPFLAGS | Array | C preprocessor flags | ["${CPPDEFPREFIX}${CPPDEFINES}"] |
|
||||||
|
| CPPPATH | Array | C preprocessor path | [] |
|
||||||
|
| CSUFFIX | Array | C source file suffixes | [".c"] |
|
||||||
|
| CXX | String | C++ compiler executable | "g++" |
|
||||||
|
| CXXCMD | Array | C++ compiler command line | ["${CXX}", "-c", "-o", "${_TARGET}", "${CXXDEPGEN}", "${INCPREFIX}${CPPPATH}", "${CPPFLAGS}", "${CXXFLAGS}", "${CCFLAGS}", "${_SOURCES}"] |
|
||||||
|
| CXXDEPGEN | Array | C++ compiler dependency generation flags | ["-MMD", "-MF", "${_DEPFILE}", "-MT", "TARGET"] |
|
||||||
|
| CXXFLAGS | Array | C++ compiler flags | [] |
|
||||||
|
| CXXSUFFIX | Array | C++ source file suffixes | [".cc", ".cpp", ".cxx", ".C"] |
|
||||||
|
| D_IMPORT_PATH | Array | D compiler import path | [] |
|
||||||
|
| DC | String | D compiler executable | "gdc" |
|
||||||
|
| DCCMD | Array | D compiler command line | ["${DC}", "-c", "-o", "${_TARGET}", "${DDEPGEN}", "${INCPREFIX}${D_IMPORT_PATH}", "${DFLAGS}", "${_SOURCES}"] |
|
||||||
|
| DDEPGEN | Array | D compiler dependency generation flags | ["-MMD", "-MF", "${_DEPFILE}", "-MT", "TARGET"] |
|
||||||
|
| DEPFILESUFFIX | String | Dependency file suffix for Makefile-style dependency rules emitted by the compiler (used internally for temporary dependency files used to determine a source file's dependencies) | ".mf" |
|
||||||
|
| DFLAGS | Array | D compiler flags | [] |
|
||||||
|
| DISASM_CMD | Array | Disassemble command line | ["${OBJDUMP}", "${DISASM_FLAGS}", "${_SOURCES}"] |
|
||||||
|
| DISASM_FLAGS | Array | Disassemble flags | ["--disassemble", "--source"] |
|
||||||
|
| DSUFFIX | String/Array | Default D source file suffix | ".d" |
|
||||||
|
| INCPREFIX | String | Prefix used for C preprocessor to add an include path | "-I" |
|
||||||
|
| LD | String | nil | Linker executable (automatically determined when nil) | nil (if nil, ${CC}, ${CXX}, or ${DC} is used depending on the sources being linked) |
|
||||||
|
| LDCMD | Array | Link command line | ["${LD}", "-o", "${_TARGET}", "${LDFLAGS}", "${_SOURCES}", "${LIBDIRPREFIX}${LIBPATH}", "${LIBLINKPREFIX}${LIBS}"] |
|
||||||
|
| LDFLAGS | Array | Linker flags | [] |
|
||||||
|
| LEX | String | Lex executable | "flex" |
|
||||||
|
| LEX_CMD | Array | Lex command line | ["${LEX}", "${LEX_FLAGS}", "-o", "${_TARGET}", "${_SOURCES}"] |
|
||||||
|
| LEX_FLAGS | Array | Lex flags | [] |
|
||||||
|
| LEXSUFFIX | Array | Lex input file suffixes | [".l", ".ll"] |
|
||||||
|
| LIBDIRPREFIX | String | Prefix given to linker to add a library search path | "-L" |
|
||||||
|
| LIBLINKPREFIX | String | Prefix given to linker to add a library to link with | "-l" |
|
||||||
|
| LIBPATH | Array | Library load path | [] |
|
||||||
|
| LIBS | Array | Libraries to link with | [] |
|
||||||
|
| LIBSUFFIX | String/Array | Default static library file suffix | ".a" |
|
||||||
|
| OBJDUMP | String | Objdump executable | "objdump" |
|
||||||
|
| OBJSUFFIX | String/Array | Default object file suffix | ".o" |
|
||||||
|
| PROGSUFFIX | String | Default program suffix. | Windows: ".exe", POSIX: "" |
|
||||||
|
| SHCC | String | Shared object C compiler | "${CC}" |
|
||||||
|
| SHCCCMD | Array | Shared object C compiler command line | ["${SHCC}", "-c", "-o", "${_TARGET}", "${CCDEPGEN}", "${INCPREFIX}${CPPPATH}", "${CPPFLAGS}", "${SHCFLAGS}", "${SHCCFLAGS}", "${_SOURCES}"] |
|
||||||
|
| SHCCFLAGS | Array | Shared object C and C++ compiler flags | Windows: ["${CCFLAGS}"], POSIX: ["${CCFLAGS}", -fPIC"] |
|
||||||
|
| SHCFLAGS | Array | Shared object C compiler flags | ["${CFLAGS}"] |
|
||||||
|
| SHCXX | String | Shared object C++ compiler | "${CXX}" |
|
||||||
|
| SHCXXCMD | Array | Shared object C++ compiler command line | ["${SHCXX}", "-c", "-o", "${_TARGET}", "${CXXDEPGEN}", "${INCPREFIX}${CPPPATH}", "${CPPFLAGS}", "${SHCXXFLAGS}", "${SHCCFLAGS}", "${_SOURCES}"] |
|
||||||
|
| SHCXXFLAGS | Array | Shared object C++ compiler flags | ["${CXXFLAGS}"] |
|
||||||
|
| SHDC | String | Shared object D compiler | "gdc" |
|
||||||
|
| SHDCCMD | Array | Shared object D compiler command line | ["${SHDC}", "-c", "-o", "${_TARGET}", "${INCPREFIX}${D_IMPORT_PATH}", "${SHDFLAGS}", "${_SOURCES}"] |
|
||||||
|
| SHDFLAGS | Array | Shared object D compiler flags | Windows: ["${DFLAGS}"], POSIX: ["${DFLAGS}", "-fPIC"] |
|
||||||
|
| SHLD | String | Shared library linker | nil (if nil, ${SHCC}, ${SHCXX}, or ${SHDC} is used depending on the sources being linked) |
|
||||||
|
| SHLDCMD | Array | Shared library linker command line | ["${SHLD}", "-o", "${_TARGET}", "${SHLDFLAGS}", "${_SOURCES}", "${SHLIBDIRPREFIX}${LIBPATH}", "${SHLIBLINKPREFIX}${LIBS}"] |
|
||||||
|
| SHLDFLAGS | Array | Shared library linker flags | ["${LDFLAGS}", "-shared"] |
|
||||||
|
| SHLIBDIRPREFIX | String | Prefix given to shared library linker to add a library search path | "-L" |
|
||||||
|
| SHLIBLINKPREFIX | String | Prefix given to shared library linker to add a library to link with | "-l" |
|
||||||
|
| SHLIBPREFIX | String | Shared library file name prefix | Windows: "", POSIX: "lib" |
|
||||||
|
| SHLIBSUFFIX | String | Shared library file name suffix | Windows: ".dll", POSIX: ".so" |
|
||||||
|
| SIZE | String | Size executable. | "size" |
|
||||||
|
| YACC | String | Yacc executable | "bison" |
|
||||||
|
| YACC_CMD | Array | Yacc command line | ["${YACC}", "${YACC_FLAGS}", "-o", "${_TARGET}", "${_SOURCES}"] |
|
||||||
|
| YACC_FLAGS | Array | Yacc flags | ["-d"] |
|
||||||
|
| YACCSUFFIX | Array | Yacc input file suffixes | [".y", ".yy"] |
|
||||||
|
|
||||||
|
### Build Hooks
|
||||||
|
|
||||||
|
Environments can have build hooks which are added with `env.add_build_hook()`.
|
||||||
|
Build hooks are invoked immediately before a builder executes.
|
||||||
|
Build hooks can modify the construction variables in use for the build
|
||||||
|
operation.
|
||||||
|
They can also register new build targets.
|
||||||
|
|
||||||
|
Environments can also have post-build hooks added with `env.add_post_build_hook()`.
|
||||||
|
Post-build hooks are only invoked if the build operation was a success.
|
||||||
|
Post-build hooks can invoke commands using the newly-built files, or register
|
||||||
|
new build targets.
|
||||||
|
|
||||||
|
Each build hook block will be invoked for every build operation, so the block
|
||||||
|
should test the target or sources if its action should only apply to some
|
||||||
|
subset of build targets or source files.
|
||||||
|
|
||||||
|
Example build hook:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
# Build third party sources without -Wall
|
||||||
|
env.add_build_hook do |build_op|
|
||||||
|
if build_op[:builder].name == "Object" and
|
||||||
|
build_op[:sources].first =~ %r{src/third-party}
|
||||||
|
build_op[:vars]["CFLAGS"] -= ["-Wall"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
The `build_op` parameter to the build hook block is a Hash describing the
|
||||||
|
build operation with the following keys:
|
||||||
|
* `:builder` - `Builder` instance in use
|
||||||
|
* `:env` - `Environment` calling the build hook; note that this may be
|
||||||
|
different from the Environment that the build hook was added to in the case
|
||||||
|
that the original Environment was cloned with build hooks!
|
||||||
|
* `:target` - `String` name of the target file
|
||||||
|
* `:sources` - `Array` of the source files
|
||||||
|
* `:vars` - `Rscons::VarSet` containing the construction variables to use.
|
||||||
|
The build hook can overwrite entries in `build_op[:vars]` to alter the
|
||||||
|
construction variables in use for this specific build operation.
|
||||||
|
|
||||||
|
### Phony Targets
|
||||||
|
|
||||||
|
A build target name given as a Symbol instead of a String is interpreted as a
|
||||||
|
"phony" target.
|
||||||
|
Phony targets operate similarly to normal build targets, except that a file is
|
||||||
|
not expected to be produced by the builder.
|
||||||
|
Phony targets will still be "rebuilt" if any source or the command is out of
|
||||||
|
date.
|
||||||
|
|
||||||
|
### Explicit Dependencies
|
||||||
|
|
||||||
|
A target can be marked as depending on another file that Rscons would not
|
||||||
|
otherwise know about via the `Environment#depends` function. For example,
|
||||||
|
to force the linker to re-link a Program output when a linker script changes:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Rscons::Environment.new do |env|
|
||||||
|
env.Program("a.out", "foo.c", "LDFLAGS" => %w[-T linker_script.ld])
|
||||||
|
env.depends("a.out", "linker_script.ld")
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
You can pass multiple dependency files to `Environment#depends`:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.depends("my_app", "config/link.ld", "README.txt", *Rscons.glob("assets/**/*"))
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command-Line Variables
|
||||||
|
|
||||||
|
Variables can be specified on the rscons command line. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
rscons VAR=val
|
||||||
|
```
|
||||||
|
|
||||||
|
These variables are accessible in a global VarSet called `Rscons.vars`.
|
||||||
|
|
||||||
|
### Construction Variable Naming
|
||||||
|
|
||||||
|
* uppercase strings - the default construction variables that Rscons uses
|
||||||
|
* strings beginning with "_" - set and used internally by builders
|
||||||
|
* symbols, lowercase strings - reserved as user-defined construction variables
|
||||||
|
|
||||||
|
### API documentation
|
||||||
|
|
||||||
|
Documentation for the complete Rscons API can be found at
|
||||||
|
http://www.rubydoc.info/github/holtrop/rscons/master.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Fork it
|
||||||
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||||
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
||||||
|
4. Push to the branch (`git push origin my-new-feature`)
|
||||||
|
5. Create new Pull Request
|
||||||
+2
-60
@@ -10,8 +10,8 @@ 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 doc coverage test]
|
||||||
CLOBBER.include %w[dist gen large_project pkg]
|
CLOBBER.include %w[dist pkg]
|
||||||
|
|
||||||
task :build_dist do
|
task :build_dist do
|
||||||
sh "ruby rb/build_dist.rb"
|
sh "ruby rb/build_dist.rb"
|
||||||
@@ -39,64 +39,6 @@ end
|
|||||||
|
|
||||||
YARD::Rake::YardocTask.new do |yard|
|
YARD::Rake::YardocTask.new do |yard|
|
||||||
yard.files = ['lib/**/*.rb']
|
yard.files = ['lib/**/*.rb']
|
||||||
yard.options = ["-ogen/yard"]
|
|
||||||
end
|
|
||||||
|
|
||||||
task :gen_large_project, [:size] => :build_dist do |task, args|
|
|
||||||
size = (args.size || 10000).to_i
|
|
||||||
FileUtils.rm_rf("large_project")
|
|
||||||
FileUtils.mkdir_p("large_project/src")
|
|
||||||
size.times do |i|
|
|
||||||
File.open("large_project/src/fn#{i}.c", "w") do |fh|
|
|
||||||
fh.puts(<<-EOF)
|
|
||||||
int fn#{i}(void)
|
|
||||||
{
|
|
||||||
return #{i};
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
File.open("large_project/src/fn#{i}.h", "w") do |fh|
|
|
||||||
fh.puts %[int fn#{i}(void);]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
File.open("large_project/src/main.c", "w") do |fh|
|
|
||||||
size.times do |i|
|
|
||||||
fh.puts %[#include "fn#{i}.h"]
|
|
||||||
end
|
|
||||||
fh.puts <<-EOF
|
|
||||||
int main(int argc, char * argv[])
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
EOF
|
|
||||||
size.times do |i|
|
|
||||||
fh.puts %[result += fn#{i}();]
|
|
||||||
end
|
|
||||||
fh.puts <<-EOF
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
File.open("large_project/Rsconscript", "w") do |fh|
|
|
||||||
fh.puts <<EOF
|
|
||||||
build do
|
|
||||||
Environment.new do |env|
|
|
||||||
env.Program("project", glob("src/*.c"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
FileUtils.cp("dist/rscons", "large_project")
|
|
||||||
end
|
|
||||||
|
|
||||||
task :user_guide do
|
|
||||||
system("ruby", "-Ilib", "rb/gen_user_guide.rb")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
task :default => :spec
|
task :default => :spec
|
||||||
|
|
||||||
task :all => [
|
|
||||||
:build_dist,
|
|
||||||
:spec,
|
|
||||||
:yard,
|
|
||||||
:user_guide,
|
|
||||||
]
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
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", set_define: "HAVE_NOT___FOUND_H"
|
check_c_header "not___found.h", fail: false, set_define: "HAVE_NOT___FOUND_H"
|
||||||
end
|
end
|
||||||
|
|
||||||
build do
|
build do
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
configure do
|
|
||||||
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,5 +0,0 @@
|
|||||||
build do
|
|
||||||
Environment.new(echo: :command) do |env|
|
|
||||||
env.Library("usr2/libfrobulous.a", "two.c")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
int two(void)
|
|
||||||
{
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
@@ -7,10 +7,10 @@ build do
|
|||||||
env.depends("${build_root}/program.o", "${inc_h}")
|
env.depends("${build_root}/program.o", "${inc_h}")
|
||||||
env.Program("program.exe", ["program.c", "inc.c"])
|
env.Program("program.exe", ["program.c", "inc.c"])
|
||||||
|
|
||||||
inc_c = env.Command("inc.c",
|
env.Command("inc.c",
|
||||||
[],
|
[],
|
||||||
"CMD" => %w[ruby gen.rb ${_TARGET}],
|
"CMD" => %w[ruby gen.rb ${_TARGET}],
|
||||||
"CMD_DESC" => "Generating")
|
"CMD_DESC" => "Generating")
|
||||||
inc_c.produces("inc.h")
|
env.produces("inc.c", "inc.h")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
build do
|
|
||||||
Environment.new do |env|
|
|
||||||
env["build_root"] = env.build_root
|
|
||||||
env["inc_h"] = "inc.h"
|
|
||||||
|
|
||||||
env.Copy("copy_inc.h", "${inc_h}")
|
|
||||||
env.depends("${build_root}/program.o", "${inc_h}")
|
|
||||||
env.Program("program.exe", ["program.c", "inc.c"])
|
|
||||||
|
|
||||||
env.Command("inc.c",
|
|
||||||
[],
|
|
||||||
"CMD" => %w[ruby gen.rb ${_TARGET}],
|
|
||||||
"CMD_DESC" => "Generating")
|
|
||||||
env.produces("inc.c", "inc.h")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
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"))
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
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,6 +0,0 @@
|
|||||||
build do
|
|
||||||
Environment.new do |env|
|
|
||||||
env.Program("program.exe", "program.c")
|
|
||||||
env.Install("install/program.exe", "program.exe")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
int main(int argc, char * argv[])
|
|
||||||
{
|
|
||||||
sleep(2);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
build do
|
build do
|
||||||
Environment.new do |env|
|
Environment.new do |env|
|
||||||
env["LIBS"] += ["m"]
|
env["LIBS"] += ["c"]
|
||||||
env.Program('simple.exe', Dir['*.c'])
|
env.Program('simple.exe', Dir['*.c'])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
build do
|
|
||||||
Environment.new do |env|
|
|
||||||
env.produces("foo", "bar")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,14 +1,5 @@
|
|||||||
project_name "install_test"
|
|
||||||
|
|
||||||
build do
|
build do
|
||||||
Environment.new do |env|
|
Environment.new do |env|
|
||||||
env["CPPPATH"] += glob("src/**")
|
env.Install("inst.exe", "install.rb")
|
||||||
env.Program("^/program.exe", glob("src/**/*.c"))
|
|
||||||
env.InstallDirectory("${prefix}/bin")
|
|
||||||
env.Install("${prefix}/bin", "^/program.exe")
|
|
||||||
env.InstallDirectory("${prefix}/share")
|
|
||||||
env.Install("${prefix}/share/proj/install.rb", "install.rb")
|
|
||||||
env.Install("${prefix}/mult", ["install.rb", "copy.rb"])
|
|
||||||
env.Install("${prefix}/src", "src")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
build do
|
|
||||||
Environment.new do |env|
|
|
||||||
env["CPPPATH"] += glob("src/**")
|
|
||||||
env.Program("^/prog.exe", glob("src/**/*.c"))
|
|
||||||
end
|
|
||||||
|
|
||||||
Environment.new do |env|
|
|
||||||
env["CPPPATH"] += glob("src/**")
|
|
||||||
env["CCFLAGS"] += %w[-Wall -g]
|
|
||||||
env.Program("^/prog-debug.exe", glob("src/**/*.c"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-1327
File diff suppressed because it is too large.
Load diff
Binary file not shown.
|
Before Width: | Height: | Size: 242 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 67 KiB |
+1
-2
@@ -26,7 +26,6 @@ module Rscons
|
|||||||
:Directory,
|
:Directory,
|
||||||
:Disassemble,
|
:Disassemble,
|
||||||
:Install,
|
:Install,
|
||||||
:InstallDirectory,
|
|
||||||
:Library,
|
:Library,
|
||||||
:Object,
|
:Object,
|
||||||
:Preprocess,
|
:Preprocess,
|
||||||
@@ -146,9 +145,9 @@ require_relative "rscons/builders/mixins/program"
|
|||||||
# default builders
|
# default builders
|
||||||
require_relative "rscons/builders/cfile"
|
require_relative "rscons/builders/cfile"
|
||||||
require_relative "rscons/builders/command"
|
require_relative "rscons/builders/command"
|
||||||
require_relative "rscons/builders/copy"
|
|
||||||
require_relative "rscons/builders/directory"
|
require_relative "rscons/builders/directory"
|
||||||
require_relative "rscons/builders/disassemble"
|
require_relative "rscons/builders/disassemble"
|
||||||
|
require_relative "rscons/builders/install"
|
||||||
require_relative "rscons/builders/library"
|
require_relative "rscons/builders/library"
|
||||||
require_relative "rscons/builders/object"
|
require_relative "rscons/builders/object"
|
||||||
require_relative "rscons/builders/preprocess"
|
require_relative "rscons/builders/preprocess"
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ 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.
|
||||||
|
|||||||
+28
-94
@@ -1,5 +1,3 @@
|
|||||||
require "set"
|
|
||||||
|
|
||||||
module Rscons
|
module Rscons
|
||||||
|
|
||||||
# Functionality for an instance of the rscons application invocation.
|
# Functionality for an instance of the rscons application invocation.
|
||||||
@@ -25,19 +23,6 @@ module Rscons
|
|||||||
def initialize
|
def initialize
|
||||||
@n_threads = Util.determine_n_threads
|
@n_threads = Util.determine_n_threads
|
||||||
@vars = VarSet.new
|
@vars = VarSet.new
|
||||||
@operations = Set.new
|
|
||||||
@build_step = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check whether a requested operation is active.
|
|
||||||
#
|
|
||||||
# @param op [String]
|
|
||||||
# Operation name.
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
# Whether the requested operation is active.
|
|
||||||
def operation(op)
|
|
||||||
@operations.include?(op)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Run the specified operation.
|
# Run the specified operation.
|
||||||
@@ -48,73 +33,35 @@ module Rscons
|
|||||||
# The script.
|
# The script.
|
||||||
# @param operation_options [Hash]
|
# @param operation_options [Hash]
|
||||||
# Option values from the CLI for the operation.
|
# Option values from the CLI for the operation.
|
||||||
# @param options [Hash]
|
|
||||||
# Optional parameters.
|
|
||||||
# @option sub_op [Boolean]
|
|
||||||
# Whether this operation is not the top-level operation.
|
|
||||||
#
|
#
|
||||||
# @return [Integer]
|
# @return [Integer]
|
||||||
# Process exit code (0 on success).
|
# Process exit code (0 on success).
|
||||||
def run(operation, script, operation_options, options = {})
|
def run(operation, script, operation_options)
|
||||||
@start_time = Time.new
|
|
||||||
@script = script
|
@script = script
|
||||||
@operations << operation
|
|
||||||
puts "Starting '#{operation}' at #{Time.new}" if verbose
|
|
||||||
rv =
|
|
||||||
case operation
|
case operation
|
||||||
when "build"
|
when "build"
|
||||||
rv = 0
|
|
||||||
unless Cache.instance["configuration_data"]["configured"]
|
unless Cache.instance["configuration_data"]["configured"]
|
||||||
rv =
|
|
||||||
if @script.autoconf
|
if @script.autoconf
|
||||||
run("configure", script, operation_options, sub_op: false)
|
rv = run("configure", script, operation_options)
|
||||||
|
if rv != 0
|
||||||
|
return rv
|
||||||
|
end
|
||||||
else
|
else
|
||||||
$stderr.puts "Project must be configured first, and autoconf is disabled"
|
$stderr.puts "Project must be configured first, and autoconf is disabled"
|
||||||
1
|
return 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if rv == 0
|
|
||||||
build(operation_options)
|
build(operation_options)
|
||||||
end
|
|
||||||
when "clean"
|
when "clean"
|
||||||
clean
|
clean
|
||||||
when "configure"
|
when "configure"
|
||||||
configure(operation_options)
|
configure(operation_options)
|
||||||
when "distclean"
|
when "distclean"
|
||||||
distclean
|
distclean
|
||||||
when "install"
|
|
||||||
run("build", script, operation_options, sub_op: false)
|
|
||||||
when "uninstall"
|
|
||||||
uninstall
|
|
||||||
else
|
else
|
||||||
$stderr.puts "Unknown operation: #{operation}"
|
$stderr.puts "Unknown operation: #{operation}"
|
||||||
1
|
1
|
||||||
end
|
end
|
||||||
if verbose and options[:sub_op].nil?
|
|
||||||
time = Time.new
|
|
||||||
elapsed = time - @start_time
|
|
||||||
puts "'#{operation}' complete at #{time} (#{Util.format_elapsed_time(elapsed)})"
|
|
||||||
end
|
|
||||||
rv
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get the next build step number.
|
|
||||||
#
|
|
||||||
# This is used internally by the {Environment} class.
|
|
||||||
#
|
|
||||||
# @api private
|
|
||||||
def get_next_build_step
|
|
||||||
@build_step += 1
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get the total number of build steps.
|
|
||||||
#
|
|
||||||
# @return [Integer]
|
|
||||||
# The total number of build steps.
|
|
||||||
def get_total_build_steps
|
|
||||||
Environment.environments.reduce(@build_step) do |result, env|
|
|
||||||
result + env.build_steps_remaining
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -147,19 +94,17 @@ module Rscons
|
|||||||
def clean
|
def clean
|
||||||
cache = Cache.instance
|
cache = Cache.instance
|
||||||
# remove all built files
|
# remove all built files
|
||||||
cache.targets(false).each do |target|
|
cache.targets.each do |target|
|
||||||
cache.remove_target(target)
|
|
||||||
FileUtils.rm_f(target)
|
FileUtils.rm_f(target)
|
||||||
end
|
end
|
||||||
# remove all created directories if they are empty
|
# remove all created directories if they are empty
|
||||||
cache.directories(false).sort {|a, b| b.size <=> a.size}.each do |directory|
|
cache.directories.sort {|a, b| b.size <=> a.size}.each do |directory|
|
||||||
cache.remove_directory(directory)
|
|
||||||
next unless File.directory?(directory)
|
next unless File.directory?(directory)
|
||||||
if (Dir.entries(directory) - ['.', '..']).empty?
|
if (Dir.entries(directory) - ['.', '..']).empty?
|
||||||
Dir.rmdir(directory) rescue nil
|
Dir.rmdir(directory) rescue nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
cache.write
|
cache.clear
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -171,9 +116,7 @@ module Rscons
|
|||||||
cache = Cache.instance
|
cache = Cache.instance
|
||||||
build_dir = cache["configuration_data"]["build_dir"]
|
build_dir = cache["configuration_data"]["build_dir"]
|
||||||
clean
|
clean
|
||||||
if build_dir
|
|
||||||
FileUtils.rm_rf(build_dir)
|
FileUtils.rm_rf(build_dir)
|
||||||
end
|
|
||||||
cache.clear
|
cache.clear
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
@@ -186,43 +129,34 @@ module Rscons
|
|||||||
# @return [Integer]
|
# @return [Integer]
|
||||||
# Exit code.
|
# Exit code.
|
||||||
def configure(options)
|
def configure(options)
|
||||||
|
# Default options.
|
||||||
|
options[:build_dir] ||= "build"
|
||||||
|
options[:prefix] ||= "/usr/local"
|
||||||
|
cache = Cache.instance
|
||||||
|
cache["failed_commands"] = []
|
||||||
|
cache["configuration_data"] = {}
|
||||||
|
if project_name = @script.project_name
|
||||||
|
Ansi.write($stdout, "Configuring ", :cyan, project_name, :reset, "...\n")
|
||||||
|
else
|
||||||
|
$stdout.puts "Configuring project..."
|
||||||
|
end
|
||||||
|
Ansi.write($stdout, "Setting build directory... ", :green, options[:build_dir], :reset, "\n")
|
||||||
|
Ansi.write($stdout, "Setting prefix... ", :green, options[:prefix], :reset, "\n")
|
||||||
rv = 0
|
rv = 0
|
||||||
options = options.merge(project_name: @script.project_name)
|
co = ConfigureOp.new("#{options[:build_dir]}/configure")
|
||||||
co = ConfigureOp.new(options)
|
|
||||||
begin
|
begin
|
||||||
@script.configure(co)
|
@script.configure(co)
|
||||||
rescue ConfigureOp::ConfigureFailure
|
rescue ConfigureOp::ConfigureFailure
|
||||||
rv = 1
|
rv = 1
|
||||||
end
|
end
|
||||||
co.close(rv == 0)
|
co.close
|
||||||
|
cache["configuration_data"]["build_dir"] = options[:build_dir]
|
||||||
|
cache["configuration_data"]["prefix"] = options[:prefix]
|
||||||
|
cache["configuration_data"]["configured"] = rv == 0
|
||||||
|
cache.write
|
||||||
rv
|
rv
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove installed files.
|
|
||||||
#
|
|
||||||
# @return [Integer]
|
|
||||||
# Exit code.
|
|
||||||
def uninstall
|
|
||||||
cache = Cache.instance
|
|
||||||
cache.targets(true).each do |target|
|
|
||||||
cache.remove_target(target)
|
|
||||||
next unless File.exists?(target)
|
|
||||||
puts "Removing #{target}" if verbose
|
|
||||||
FileUtils.rm_f(target)
|
|
||||||
end
|
|
||||||
# remove all created directories if they are empty
|
|
||||||
cache.directories(true).sort {|a, b| b.size <=> a.size}.each do |directory|
|
|
||||||
cache.remove_directory(directory)
|
|
||||||
next unless File.directory?(directory)
|
|
||||||
if (Dir.entries(directory) - ['.', '..']).empty?
|
|
||||||
puts "Removing #{directory}" if verbose
|
|
||||||
Dir.rmdir(directory) rescue nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
cache.write
|
|
||||||
0
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -4,52 +4,27 @@ 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)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Access the value of a construction variable.
|
# Get a construction variable's value.
|
||||||
#
|
#
|
||||||
# @param key [String, Symbol]
|
# @see VarSet#[]
|
||||||
# The construction variable name.
|
def [](*args)
|
||||||
#
|
@varset.__send__(:[], *args)
|
||||||
# @return [Object]
|
|
||||||
# The construction variable's value.
|
|
||||||
def [](key)
|
|
||||||
@varset[key]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Access the value of a construction variable.
|
# Set a construction variable's value.
|
||||||
#
|
#
|
||||||
# This method is similar to #[] but does not make a copy-on-access copy of
|
# @see VarSet#[]=
|
||||||
# the variable accessed. This means that the returned value is NOT safe to
|
def []=(*args)
|
||||||
# be modified by the caller. Thus the caller must guarantee that it does
|
@varset.__send__(:[]=, *args)
|
||||||
# not modify the returned value.
|
|
||||||
#
|
|
||||||
# @param key [String, Symbol]
|
|
||||||
# The construction variable name.
|
|
||||||
#
|
|
||||||
# @return [Object]
|
|
||||||
# The construction variable's value.
|
|
||||||
def get_var(key)
|
|
||||||
@varset.get_var(key)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Assign a value to a construction variable.
|
|
||||||
#
|
|
||||||
# @param key [String, Symbol]
|
|
||||||
# The construction variable name.
|
|
||||||
#
|
|
||||||
# @param val [Object]
|
|
||||||
# The value to set.
|
|
||||||
def []=(key, val)
|
|
||||||
@varset[key] = val
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add a set of construction variables to the BasicEnvironment.
|
# Add a set of construction variables to the BasicEnvironment.
|
||||||
@@ -133,7 +108,7 @@ module Rscons
|
|||||||
append["LDFLAGS", ["-arch", val]]
|
append["LDFLAGS", ["-arch", val]]
|
||||||
end
|
end
|
||||||
skip = true
|
skip = true
|
||||||
elsif word =~ /^#{get_var("CPPDEFPREFIX")}(.*)$/
|
elsif word =~ /^#{self["CPPDEFPREFIX"]}(.*)$/
|
||||||
handle["CPPDEFINES", $1]
|
handle["CPPDEFINES", $1]
|
||||||
elsif word == "-include"
|
elsif word == "-include"
|
||||||
if val = words[i + 1]
|
if val = words[i + 1]
|
||||||
@@ -146,11 +121,11 @@ module Rscons
|
|||||||
append["LDFLAGS", ["-isysroot", val]]
|
append["LDFLAGS", ["-isysroot", val]]
|
||||||
end
|
end
|
||||||
skip = true
|
skip = true
|
||||||
elsif word =~ /^#{get_var("INCPREFIX")}(.*)$/
|
elsif word =~ /^#{self["INCPREFIX"]}(.*)$/
|
||||||
handle["CPPPATH", $1]
|
handle["CPPPATH", $1]
|
||||||
elsif word =~ /^#{get_var("LIBLINKPREFIX")}(.*)$/
|
elsif word =~ /^#{self["LIBLINKPREFIX"]}(.*)$/
|
||||||
handle["LIBS", $1]
|
handle["LIBS", $1]
|
||||||
elsif word =~ /^#{get_var("LIBDIRPREFIX")}(.*)$/
|
elsif word =~ /^#{self["LIBDIRPREFIX"]}(.*)$/
|
||||||
handle["LIBPATH", $1]
|
handle["LIBPATH", $1]
|
||||||
elsif word == "-mno-cygwin"
|
elsif word == "-mno-cygwin"
|
||||||
append["CCFLAGS", [word]]
|
append["CCFLAGS", [word]]
|
||||||
@@ -199,7 +174,7 @@ module Rscons
|
|||||||
# @return [void]
|
# @return [void]
|
||||||
def merge_flags(flags)
|
def merge_flags(flags)
|
||||||
flags.each_pair do |key, val|
|
flags.each_pair do |key, val|
|
||||||
if self.get_var(key).is_a?(Array) and val.is_a?(Array)
|
if self[key].is_a?(Array) and val.is_a?(Array)
|
||||||
self[key] += val
|
self[key] += val
|
||||||
else
|
else
|
||||||
self[key] = val
|
self[key] = val
|
||||||
@@ -248,28 +223,5 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Execute a command using the system shell.
|
|
||||||
#
|
|
||||||
# The shell is automatically determined but can be overridden by the SHELL
|
|
||||||
# construction variable. If the SHELL construction variable is specified,
|
|
||||||
# the flag to pass to the shell is automatically dtermined but can be
|
|
||||||
# overridden by the SHELLFLAG construction variable.
|
|
||||||
#
|
|
||||||
# @param command [String] Command to execute.
|
|
||||||
#
|
|
||||||
# @return [String] The command's standard output.
|
|
||||||
def shell(command)
|
|
||||||
shell_cmd =
|
|
||||||
if shell = get_var("SHELL")
|
|
||||||
flag = get_var("SHELLFLAG") || (shell == "cmd" ? "/c" : "-c")
|
|
||||||
[shell, flag]
|
|
||||||
else
|
|
||||||
Rscons.get_system_shell
|
|
||||||
end
|
|
||||||
IO.popen([*shell_cmd, command]) do |io|
|
|
||||||
io.read
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
+2
-29
@@ -47,14 +47,6 @@ module Rscons
|
|||||||
# Construction variables used to perform the build operation.
|
# Construction variables used to perform the build operation.
|
||||||
attr_accessor :vars
|
attr_accessor :vars
|
||||||
|
|
||||||
# @return [Set<String>]
|
|
||||||
# Side effect file(s) produced when this builder runs.
|
|
||||||
attr_accessor :side_effects
|
|
||||||
|
|
||||||
# @return [Integer]
|
|
||||||
# Build step.
|
|
||||||
attr_accessor :build_step
|
|
||||||
|
|
||||||
# Create an instance of the Builder to build a target.
|
# Create an instance of the Builder to build a target.
|
||||||
#
|
#
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
@@ -75,7 +67,6 @@ module Rscons
|
|||||||
@cache = options[:cache]
|
@cache = options[:cache]
|
||||||
@env = options[:env]
|
@env = options[:env]
|
||||||
@vars = options[:vars]
|
@vars = options[:vars]
|
||||||
@side_effects = Set.new
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return the name of the builder.
|
# Return the name of the builder.
|
||||||
@@ -87,14 +78,6 @@ module Rscons
|
|||||||
self.class.name
|
self.class.name
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return whether the builder is a no-op.
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
# Whether the builder is a no-op.
|
|
||||||
def nop?
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Manually record a given build target as depending on the specified files.
|
# Manually record a given build target as depending on the specified files.
|
||||||
#
|
#
|
||||||
# @param user_deps [Array<String>]
|
# @param user_deps [Array<String>]
|
||||||
@@ -105,18 +88,6 @@ module Rscons
|
|||||||
@env.depends(@target, *user_deps)
|
@env.depends(@target, *user_deps)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Manually record the given side effect file(s) as being produced when the
|
|
||||||
# named target is produced.
|
|
||||||
#
|
|
||||||
# @return [void]
|
|
||||||
def produces(*side_effects)
|
|
||||||
side_effects.each do |side_effect|
|
|
||||||
side_effect_expanded = @env.expand_path(@env.expand_varref(side_effect))
|
|
||||||
@env.register_side_effect(side_effect_expanded)
|
|
||||||
@side_effects << side_effect_expanded
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
#
|
#
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
@@ -201,6 +172,8 @@ module Rscons
|
|||||||
|
|
||||||
# Register build results from a {Command} with the cache.
|
# Register build results from a {Command} with the cache.
|
||||||
#
|
#
|
||||||
|
# @since 1.10.0
|
||||||
|
#
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# Builder finalize options.
|
# Builder finalize options.
|
||||||
# @option options [String] :stdout
|
# @option options [String] :stdout
|
||||||
|
|||||||
+17
-29
@@ -8,10 +8,10 @@ module Rscons
|
|||||||
# Hash mapping targets to a set of build dependencies. A builder will not
|
# Hash mapping targets to a set of build dependencies. A builder will not
|
||||||
# be returned as ready to run if any of its dependencies are still
|
# be returned as ready to run if any of its dependencies are still
|
||||||
# building.
|
# building.
|
||||||
# @param side_effects [Set]
|
# @param side_effects [Hash]
|
||||||
# Set of side-effect files. A builder will not be returned as ready to
|
# Hash mapping targets to a set of side-effect files. A builder will not
|
||||||
# run if any of its dependencies is a side-effect of another target that
|
# be returned as ready to run if any of its dependencies is a side-effect
|
||||||
# has not yet been built.
|
# of another target that has not yet been built.
|
||||||
def initialize(build_dependencies, side_effects)
|
def initialize(build_dependencies, side_effects)
|
||||||
super()
|
super()
|
||||||
@build_dependencies = build_dependencies
|
@build_dependencies = build_dependencies
|
||||||
@@ -31,16 +31,6 @@ module Rscons
|
|||||||
self[builder.target] << builder
|
self[builder.target] << builder
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return the number of remaining build steps.
|
|
||||||
#
|
|
||||||
# @return [Integer]
|
|
||||||
# The number of remaining build steps.
|
|
||||||
def build_steps_remaining
|
|
||||||
self.reduce(0) do |result, (target, builders)|
|
|
||||||
result + builders.select {|b| not b.nop?}.size
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get the next builder that is ready to run from the BuilderSet.
|
# Get the next builder that is ready to run from the BuilderSet.
|
||||||
#
|
#
|
||||||
# This method will remove the builder from the BuilderSet.
|
# This method will remove the builder from the BuilderSet.
|
||||||
@@ -53,24 +43,22 @@ module Rscons
|
|||||||
# @return [nil, Builder]
|
# @return [nil, Builder]
|
||||||
# The next builder to run.
|
# The next builder to run.
|
||||||
def get_next_builder_to_run(targets_still_building)
|
def get_next_builder_to_run(targets_still_building)
|
||||||
to_build = self.find do |target, builders|
|
not_built_yet = targets_still_building + self.keys
|
||||||
deps = builders.first.sources + (@build_dependencies[target] || []).to_a
|
not_built_yet += not_built_yet.reduce([]) do |result, target|
|
||||||
# All dependencies must have been built for this target to be ready to
|
result + (@side_effects[target] || [])
|
||||||
# build.
|
|
||||||
deps.all? do |dep|
|
|
||||||
!(targets_still_building.include?(dep) ||
|
|
||||||
self.include?(dep) ||
|
|
||||||
@side_effects.include?(dep))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if to_build
|
target_to_build = self.keys.find do |target|
|
||||||
target, builders = *to_build
|
deps = self[target][0].sources + (@build_dependencies[target] || []).to_a
|
||||||
builder = builders.first
|
!deps.find {|dep| not_built_yet.include?(dep)}
|
||||||
if builders.size > 1
|
end
|
||||||
builders.slice!(0)
|
|
||||||
|
if target_to_build
|
||||||
|
builder = self[target_to_build][0]
|
||||||
|
if self[target_to_build].size > 1
|
||||||
|
self[target_to_build].slice!(0)
|
||||||
else
|
else
|
||||||
self.delete(target)
|
self.delete(target_to_build)
|
||||||
end
|
end
|
||||||
return builder
|
return builder
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ module Rscons
|
|||||||
raise "Unknown source file #{@sources.first.inspect} for CFile builder"
|
raise "Unknown source file #{@sources.first.inspect} for CFile builder"
|
||||||
end
|
end
|
||||||
command = @env.build_command("${#{cmd}_CMD}", @vars)
|
command = @env.build_command("${#{cmd}_CMD}", @vars)
|
||||||
standard_command("#{message} from <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
|
standard_command("#{message} from #{Util.short_format_paths(@sources)} => #{@target}", command)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ module Rscons
|
|||||||
# A builder to execute an arbitrary command that will produce the given
|
# A builder to execute an arbitrary command that will produce the given
|
||||||
# target based on the given sources.
|
# target based on the given sources.
|
||||||
#
|
#
|
||||||
|
# @since 1.8.0
|
||||||
|
#
|
||||||
# Example:
|
# Example:
|
||||||
# env.Command("docs.html", "docs.md",
|
# env.Command("docs.html", "docs.md",
|
||||||
# CMD => %w[pandoc -fmarkdown -thtml -o${_TARGET} ${_SOURCES}])
|
# CMD => %w[pandoc -fmarkdown -thtml -o${_TARGET} ${_SOURCES}])
|
||||||
@@ -21,7 +23,7 @@ module Rscons
|
|||||||
if @vars["CMD_STDOUT"]
|
if @vars["CMD_STDOUT"]
|
||||||
options[:stdout] = @env.expand_varref("${CMD_STDOUT}", @vars)
|
options[:stdout] = @env.expand_varref("${CMD_STDOUT}", @vars)
|
||||||
end
|
end
|
||||||
standard_command("#{cmd_desc} <target>#{@target}<reset>", command, options)
|
standard_command("#{cmd_desc} => #{@target}", command, options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
require "pathname"
|
|
||||||
|
|
||||||
module Rscons
|
|
||||||
module Builders
|
|
||||||
# The Copy builder copies files/directories to new locations.
|
|
||||||
class Copy < Builder
|
|
||||||
|
|
||||||
# Construct builder.
|
|
||||||
def initialize(*args)
|
|
||||||
super
|
|
||||||
@install_builder = self.class.name == "Install"
|
|
||||||
@nop = @install_builder && !Rscons.application.operation("install")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Return whether the builder is a no-op.
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
# Whether the builder is a no-op.
|
|
||||||
def nop?
|
|
||||||
@nop
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run the builder to produce a build target.
|
|
||||||
def run(options)
|
|
||||||
if @nop
|
|
||||||
true
|
|
||||||
else
|
|
||||||
target_is_dir = (@sources.length > 1) ||
|
|
||||||
Dir.exists?(@sources.first) ||
|
|
||||||
Dir.exists?(@target)
|
|
||||||
outdir = target_is_dir ? @target : File.dirname(@target)
|
|
||||||
# Collect the list of files to copy over.
|
|
||||||
file_map = {}
|
|
||||||
if target_is_dir
|
|
||||||
@sources.each do |src|
|
|
||||||
if Dir.exists? src
|
|
||||||
Dir.glob("#{src}/**/*", File::FNM_DOTMATCH).select do |f|
|
|
||||||
File.file?(f)
|
|
||||||
end.each do |subfile|
|
|
||||||
subpath = Pathname.new(subfile).relative_path_from(Pathname.new(src)).to_s
|
|
||||||
file_map[subfile] = "#{outdir}/#{subpath}"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
file_map[src] = "#{outdir}/#{File.basename(src)}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
file_map[sources.first] = target
|
|
||||||
end
|
|
||||||
printed_message = false
|
|
||||||
file_map.each do |src, dest|
|
|
||||||
# Check the cache and copy if necessary
|
|
||||||
unless @cache.up_to_date?(dest, :Copy, [src], @env)
|
|
||||||
unless printed_message
|
|
||||||
message = "#{name} <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>"
|
|
||||||
print_run_message(message, nil)
|
|
||||||
printed_message = true
|
|
||||||
end
|
|
||||||
@cache.mkdir_p(File.dirname(dest), install: @install_builder)
|
|
||||||
FileUtils.rm_f(dest)
|
|
||||||
FileUtils.cp(src, dest, :preserve => true)
|
|
||||||
end
|
|
||||||
@cache.register_build(dest, :Copy, [src], @env, install: @install_builder)
|
|
||||||
end
|
|
||||||
(target_is_dir ? Dir.exists?(@target) : File.exists?(@target)) ? true : false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# The Install builder is identical to the Copy builder.
|
|
||||||
class Install < Copy; end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,47 +1,22 @@
|
|||||||
module Rscons
|
module Rscons
|
||||||
module Builders
|
module Builders
|
||||||
|
|
||||||
# The Directory builder creates a directory.
|
# The Directory builder creates a directory.
|
||||||
class Directory < Builder
|
class Directory < Builder
|
||||||
|
|
||||||
# Construct builder.
|
|
||||||
def initialize(*args)
|
|
||||||
super
|
|
||||||
@install_builder = self.class.name == "InstallDirectory"
|
|
||||||
@nop = @install_builder && !Rscons.application.operation("install")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Return whether the builder is a no-op.
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
# Whether the builder is a no-op.
|
|
||||||
def nop?
|
|
||||||
@nop
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
def run(options)
|
def run(options)
|
||||||
if @nop
|
|
||||||
true
|
|
||||||
else
|
|
||||||
if File.directory?(@target)
|
if File.directory?(@target)
|
||||||
true
|
true
|
||||||
elsif File.exists?(@target)
|
elsif File.exists?(@target)
|
||||||
Ansi.write($stderr, :red, "Error: `#{@target}' already exists and is not a directory", :reset, "\n")
|
Ansi.write($stderr, :red, "Error: `#{@target}' already exists and is not a directory", :reset, "\n")
|
||||||
false
|
false
|
||||||
else
|
else
|
||||||
print_run_message("Creating directory <target>#{@target}<reset>", nil)
|
print_run_message("Creating directory => #{@target}", nil)
|
||||||
@cache.mkdir_p(@target, install: @install_builder)
|
@cache.mkdir_p(@target)
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# The InstallDirectory class is identical to Directory but only performs
|
|
||||||
# an action for an "install" operation.
|
|
||||||
class InstallDirectory < Directory; end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
@@ -10,7 +10,7 @@ module Rscons
|
|||||||
else
|
else
|
||||||
@vars["_SOURCES"] = @sources
|
@vars["_SOURCES"] = @sources
|
||||||
command = @env.build_command("${DISASM_CMD}", @vars)
|
command = @env.build_command("${DISASM_CMD}", @vars)
|
||||||
standard_command("Disassembling <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{target}<reset>", command, stdout: @target)
|
standard_command("Disassembling #{Util.short_format_paths(@sources)} => #{target}", command, stdout: @target)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
require "pathname"
|
||||||
|
|
||||||
|
module Rscons
|
||||||
|
module Builders
|
||||||
|
# The Install builder copies files/directories to new locations.
|
||||||
|
class Install < Builder
|
||||||
|
|
||||||
|
# Run the builder to produce a build target.
|
||||||
|
def run(options)
|
||||||
|
target_is_dir = (@sources.length > 1) ||
|
||||||
|
Dir.exists?(@sources.first) ||
|
||||||
|
Dir.exists?(@target)
|
||||||
|
outdir = target_is_dir ? @target : File.dirname(@target)
|
||||||
|
# Collect the list of files to copy over.
|
||||||
|
file_map = {}
|
||||||
|
if target_is_dir
|
||||||
|
@sources.each do |src|
|
||||||
|
if Dir.exists? src
|
||||||
|
Dir.glob("#{src}/**/*", File::FNM_DOTMATCH).select do |f|
|
||||||
|
File.file?(f)
|
||||||
|
end.each do |subfile|
|
||||||
|
subpath = Pathname.new(subfile).relative_path_from(Pathname.new(src)).to_s
|
||||||
|
file_map[subfile] = "#{outdir}/#{subpath}"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
file_map[src] = "#{outdir}/#{File.basename(src)}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
file_map[sources.first] = target
|
||||||
|
end
|
||||||
|
printed_message = false
|
||||||
|
file_map.each do |src, dest|
|
||||||
|
# Check the cache and copy if necessary
|
||||||
|
unless @cache.up_to_date?(dest, :Copy, [src], @env)
|
||||||
|
unless printed_message
|
||||||
|
message = "#{name} #{Util.short_format_paths(@sources)} => #{@target}"
|
||||||
|
print_run_message(message, nil)
|
||||||
|
printed_message = true
|
||||||
|
end
|
||||||
|
@cache.mkdir_p(File.dirname(dest))
|
||||||
|
FileUtils.cp(src, dest, :preserve => true)
|
||||||
|
end
|
||||||
|
@cache.register_build(dest, :Copy, [src], @env)
|
||||||
|
end
|
||||||
|
(target_is_dir ? Dir.exists?(@target) : File.exists?(@target)) ? true : false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# The Copy builder is identical to the Install builder.
|
||||||
|
class Copy < Install; end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -20,7 +20,7 @@ module Rscons
|
|||||||
@vars["_TARGET"] = @target
|
@vars["_TARGET"] = @target
|
||||||
@vars["_SOURCES"] = @objects
|
@vars["_SOURCES"] = @objects
|
||||||
command = @env.build_command("${ARCMD}", @vars)
|
command = @env.build_command("${ARCMD}", @vars)
|
||||||
standard_command("Building static library archive <target>#{@target}<reset>", command, sources: @objects)
|
standard_command("Building static library archive => #{@target}", command, sources: @objects)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -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_dependency_file(@vars["_DEPFILE"])
|
deps += Util.parse_makefile_deps(@vars["_DEPFILE"])
|
||||||
end
|
end
|
||||||
@cache.register_build(@target, @command, deps.uniq, @env)
|
@cache.register_build(@target, @command, deps.uniq, @env)
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ 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
|
||||||
@@ -82,11 +81,11 @@ module Rscons
|
|||||||
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)
|
||||||
self.produces(@vars["_DEPFILE"])
|
@env.produces(@target, @vars["_DEPFILE"])
|
||||||
if @vars[:direct]
|
if @vars[:direct]
|
||||||
message = "#{@short_description}/Linking <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>"
|
message = "#{@short_description}/Linking #{Util.short_format_paths(@sources)} => #{@target}"
|
||||||
else
|
else
|
||||||
message = "#{@short_description} <source>#{Util.short_format_paths(@sources)}<reset>"
|
message = "#{@short_description} #{Util.short_format_paths(@sources)}"
|
||||||
end
|
end
|
||||||
standard_command(message, command)
|
standard_command(message, command)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ module Rscons
|
|||||||
@vars["_SOURCES"] = @objects
|
@vars["_SOURCES"] = @objects
|
||||||
@vars["#{ld_var}"] = ld
|
@vars["#{ld_var}"] = ld
|
||||||
command = @env.build_command("${#{ld_var}CMD}", @vars)
|
command = @env.build_command("${#{ld_var}CMD}", @vars)
|
||||||
standard_command("Linking <target>#{@target}<reset>", command, sources: @objects)
|
standard_command("Linking => #{@target}", command, sources: @objects)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ module Rscons
|
|||||||
@vars["_SOURCES"] = @sources
|
@vars["_SOURCES"] = @sources
|
||||||
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
||||||
command = @env.build_command("${CPP_CMD}", @vars)
|
command = @env.build_command("${CPP_CMD}", @vars)
|
||||||
self.produces(@vars["_DEPFILE"])
|
@env.produces(@target, @vars["_DEPFILE"])
|
||||||
standard_command("Preprocessing <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
|
standard_command("Preprocessing #{Util.short_format_paths(@sources)} => #{@target}", command)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ module Rscons
|
|||||||
include Mixins::Program
|
include Mixins::Program
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
# Custom new method which will delegate to the correct class depending
|
|
||||||
# on the options specified.
|
|
||||||
def new(options, *more)
|
def new(options, *more)
|
||||||
unless File.basename(options[:target])["."]
|
unless File.basename(options[:target])["."]
|
||||||
options[:target] += options[:env].expand_varref("${PROGSUFFIX}", options[:vars])
|
options[:target] += options[:env].expand_varref("${PROGSUFFIX}", options[:vars])
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ module Rscons
|
|||||||
include Mixins::Program
|
include Mixins::Program
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
# Custom new method which will delegate to the correct class depending
|
|
||||||
# on the options specified.
|
|
||||||
def new(options, *more)
|
def new(options, *more)
|
||||||
libprefix = options[:env].expand_varref("${SHLIBPREFIX}", options[:vars])
|
libprefix = options[:env].expand_varref("${SHLIBPREFIX}", options[:vars])
|
||||||
unless File.basename(options[:target]).start_with?(libprefix)
|
unless File.basename(options[:target]).start_with?(libprefix)
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ 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
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
module Rscons
|
module Rscons
|
||||||
module Builders
|
module Builders
|
||||||
# A Generic builder which has its operation is defined at instantiation.
|
# A Generic builder which has its operation is defined at instantiation.
|
||||||
|
#
|
||||||
|
# @since 1.8.0
|
||||||
class SimpleBuilder < Builder
|
class SimpleBuilder < Builder
|
||||||
|
|
||||||
# @return [String]
|
# @return [String]
|
||||||
|
|||||||
+18
-23
@@ -100,6 +100,7 @@ module Rscons
|
|||||||
# @return [void]
|
# @return [void]
|
||||||
def write
|
def write
|
||||||
@cache["version"] = VERSION
|
@cache["version"] = VERSION
|
||||||
|
validate_json_object(@cache)
|
||||||
File.open(CACHE_FILE, "w") do |fh|
|
File.open(CACHE_FILE, "w") do |fh|
|
||||||
fh.puts(JSON.dump(@cache))
|
fh.puts(JSON.dump(@cache))
|
||||||
end
|
end
|
||||||
@@ -238,18 +239,11 @@ module Rscons
|
|||||||
# @param options [Hash] Optional arguments.
|
# @param options [Hash] Optional arguments.
|
||||||
# @option options [Boolean] :install
|
# @option options [Boolean] :install
|
||||||
# Whether the target is for an install operation.
|
# Whether the target is for an install operation.
|
||||||
# @option options [Boolean] :side_effect
|
|
||||||
# Whether the target is a side-effect file (no checksum will be stored).
|
|
||||||
#
|
#
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def register_build(targets, command, deps, env, options = {})
|
def register_build(targets, command, deps, env, options = {})
|
||||||
Array(targets).each do |target|
|
Array(targets).each do |target|
|
||||||
target_checksum =
|
target_checksum = Rscons.phony_target?(target) ? "" : calculate_checksum(target)
|
||||||
if options[:side_effect] or Rscons.phony_target?(target)
|
|
||||||
""
|
|
||||||
else
|
|
||||||
calculate_checksum(target)
|
|
||||||
end
|
|
||||||
@cache["targets"][get_cache_key(target)] = {
|
@cache["targets"][get_cache_key(target)] = {
|
||||||
"command" => Digest::MD5.hexdigest(command.inspect),
|
"command" => Digest::MD5.hexdigest(command.inspect),
|
||||||
"checksum" => target_checksum,
|
"checksum" => target_checksum,
|
||||||
@@ -281,7 +275,7 @@ module Rscons
|
|||||||
def targets(install)
|
def targets(install)
|
||||||
install = !!install
|
install = !!install
|
||||||
@cache["targets"].select do |key, target|
|
@cache["targets"].select do |key, target|
|
||||||
target["install"] == install
|
target[:install] == install
|
||||||
end.map(&:first)
|
end.map(&:first)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -326,20 +320,6 @@ module Rscons
|
|||||||
end.map(&:first)
|
end.map(&:first)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove a target from the cache.
|
|
||||||
#
|
|
||||||
# @return [void]
|
|
||||||
def remove_target(target)
|
|
||||||
@cache["targets"].delete(target)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Remove a directory from the cache.
|
|
||||||
#
|
|
||||||
# @return [void]
|
|
||||||
def remove_directory(directory)
|
|
||||||
@cache["directories"].delete(directory)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Return a String key based on the target name to use in the on-disk cache.
|
# Return a String key based on the target name to use in the on-disk cache.
|
||||||
@@ -390,5 +370,20 @@ module Rscons
|
|||||||
@lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file, mode: "rb")) rescue ""
|
@lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file, mode: "rb")) rescue ""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Validate that an object is one of a known set of values that can be
|
||||||
|
# serialized properly with JSON.
|
||||||
|
#
|
||||||
|
# @param o [Object]
|
||||||
|
# Object to validate.
|
||||||
|
def validate_json_object(o)
|
||||||
|
if o.is_a?(Array)
|
||||||
|
o.each {|v| validate_json_object(v)}
|
||||||
|
elsif o.is_a?(Hash)
|
||||||
|
o.each {|*kv| validate_json_object(kv)}
|
||||||
|
elsif [NilClass, TrueClass, FalseClass, String].none? {|c| o.is_a?(c)}
|
||||||
|
raise "Unexpected cache value for serialization: #{o.inspect}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
+10
-14
@@ -1,12 +1,11 @@
|
|||||||
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 failed command log from previous build and exit
|
-F, --show-failure Show previous failed command(s) and exit
|
||||||
--version Show rscons version and exit
|
--version Show rscons version and exit
|
||||||
-h, --help Show rscons help and exit
|
-h, --help Show rscons help and exit
|
||||||
-r COLOR, --color=COLOR Set color mode (off, auto, force)
|
-r COLOR, --color=COLOR Set color mode (off, auto, force)
|
||||||
@@ -122,23 +121,20 @@ module Rscons
|
|||||||
rsconscript = DEFAULT_RSCONSCRIPTS.find do |f|
|
rsconscript = DEFAULT_RSCONSCRIPTS.find do |f|
|
||||||
File.exists?(f)
|
File.exists?(f)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if rsconscript
|
|
||||||
script = Script.new
|
|
||||||
script.load(rsconscript)
|
|
||||||
end
|
|
||||||
|
|
||||||
if do_help
|
|
||||||
puts USAGE
|
|
||||||
exit 0
|
|
||||||
end
|
|
||||||
|
|
||||||
unless rsconscript
|
unless rsconscript
|
||||||
$stderr.puts "Could not find the Rsconscript to execute."
|
$stderr.puts "Could not find the Rsconscript to execute."
|
||||||
$stderr.puts "Looked for: #{DEFAULT_RSCONSCRIPTS.join(", ")}"
|
$stderr.puts "Looked for: #{DEFAULT_RSCONSCRIPTS.join(", ")}"
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
script = Script.new
|
||||||
|
script.load(rsconscript)
|
||||||
|
|
||||||
|
if do_help
|
||||||
|
puts USAGE
|
||||||
|
exit 0
|
||||||
|
end
|
||||||
|
|
||||||
operation_options = parse_operation_args(operation, argv) || {}
|
operation_options = parse_operation_args(operation, argv) || {}
|
||||||
|
|
||||||
|
|||||||
+108
-231
@@ -10,48 +10,20 @@ module Rscons
|
|||||||
|
|
||||||
# Create a ConfigureOp.
|
# Create a ConfigureOp.
|
||||||
#
|
#
|
||||||
# @param options [Hash]
|
# @param work_dir [String]
|
||||||
# Optional parameters.
|
# Work directory for configure operation.
|
||||||
# @option options [String] :build_dir
|
def initialize(work_dir)
|
||||||
# Build directory.
|
@work_dir = work_dir
|
||||||
# @option options [String] :prefix
|
|
||||||
# Install prefix.
|
|
||||||
# @option options [String] :project_name
|
|
||||||
# Project name.
|
|
||||||
def initialize(options)
|
|
||||||
# Default options.
|
|
||||||
options[:build_dir] ||= "build"
|
|
||||||
options[:prefix] ||= "/usr/local"
|
|
||||||
@work_dir = "#{options[:build_dir]}/configure"
|
|
||||||
FileUtils.mkdir_p(@work_dir)
|
FileUtils.mkdir_p(@work_dir)
|
||||||
@log_fh = File.open("#{@work_dir}/config.log", "wb")
|
@log_fh = File.open("#{@work_dir}/config.log", "wb")
|
||||||
cache = Cache.instance
|
|
||||||
cache["failed_commands"] = []
|
|
||||||
cache["configuration_data"] = {}
|
|
||||||
cache["configuration_data"]["build_dir"] = options[:build_dir]
|
|
||||||
cache["configuration_data"]["prefix"] = options[:prefix]
|
|
||||||
if project_name = options[:project_name]
|
|
||||||
Ansi.write($stdout, "Configuring ", :cyan, project_name, :reset, "...\n")
|
|
||||||
else
|
|
||||||
$stdout.puts "Configuring project..."
|
|
||||||
end
|
|
||||||
Ansi.write($stdout, "Setting build directory... ", :green, options[:build_dir], :reset, "\n")
|
|
||||||
Ansi.write($stdout, "Setting prefix... ", :green, options[:prefix], :reset, "\n")
|
|
||||||
store_merge("prefix" => options[:prefix])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Close the log file handle.
|
# Close the log file handle.
|
||||||
#
|
#
|
||||||
# @param success [Boolean]
|
|
||||||
# Whether all configure operations were successful.
|
|
||||||
#
|
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def close(success)
|
def close
|
||||||
@log_fh.close
|
@log_fh.close
|
||||||
@log_fh = nil
|
@log_fh = nil
|
||||||
cache = Cache.instance
|
|
||||||
cache["configuration_data"]["configured"] = success
|
|
||||||
cache.write
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a working C compiler.
|
# Check for a working C compiler.
|
||||||
@@ -69,7 +41,7 @@ module Rscons
|
|||||||
cc = ccc.find do |cc|
|
cc = ccc.find do |cc|
|
||||||
test_c_compiler(cc)
|
test_c_compiler(cc)
|
||||||
end
|
end
|
||||||
complete(cc ? 0 : 1, success_message: cc)
|
common_config_checks(cc ? 0 : 1, success_message: cc)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a working C++ compiler.
|
# Check for a working C++ compiler.
|
||||||
@@ -87,7 +59,7 @@ module Rscons
|
|||||||
cc = ccc.find do |cc|
|
cc = ccc.find do |cc|
|
||||||
test_cxx_compiler(cc)
|
test_cxx_compiler(cc)
|
||||||
end
|
end
|
||||||
complete(cc ? 0 : 1, success_message: cc)
|
common_config_checks(cc ? 0 : 1, success_message: cc)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a working D compiler.
|
# Check for a working D compiler.
|
||||||
@@ -105,7 +77,7 @@ module Rscons
|
|||||||
dc = cdc.find do |dc|
|
dc = cdc.find do |dc|
|
||||||
test_d_compiler(dc)
|
test_d_compiler(dc)
|
||||||
end
|
end
|
||||||
complete(dc ? 0 : 1, success_message: dc)
|
common_config_checks(dc ? 0 : 1, success_message: dc)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for a package or configure program output.
|
# Check for a package or configure program output.
|
||||||
@@ -122,12 +94,11 @@ module Rscons
|
|||||||
if status == 0
|
if status == 0
|
||||||
store_parse(stdout, options)
|
store_parse(stdout, options)
|
||||||
end
|
end
|
||||||
complete(status, options)
|
common_config_checks(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
|
||||||
@@ -140,30 +111,15 @@ module Rscons
|
|||||||
vars = {
|
vars = {
|
||||||
"LD" => "${CC}",
|
"LD" => "${CC}",
|
||||||
"_SOURCES" => "#{@work_dir}/cfgtest.c",
|
"_SOURCES" => "#{@work_dir}/cfgtest.c",
|
||||||
"_TARGET" => "#{@work_dir}/cfgtest.o",
|
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
||||||
"_DEPFILE" => "#{@work_dir}/cfgtest.mf",
|
|
||||||
}
|
}
|
||||||
status = 1
|
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
||||||
check_cpppath.each do |cpppath|
|
|
||||||
env = BasicEnvironment.new
|
|
||||||
if cpppath
|
|
||||||
env["CPPPATH"] += Array(cpppath)
|
|
||||||
end
|
|
||||||
command = env.build_command("${CCCMD}", vars)
|
|
||||||
_, _, status = log_and_test_command(command)
|
_, _, status = log_and_test_command(command)
|
||||||
if status == 0
|
common_config_checks(status, options)
|
||||||
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
|
||||||
@@ -176,30 +132,15 @@ module Rscons
|
|||||||
vars = {
|
vars = {
|
||||||
"LD" => "${CXX}",
|
"LD" => "${CXX}",
|
||||||
"_SOURCES" => "#{@work_dir}/cfgtest.cxx",
|
"_SOURCES" => "#{@work_dir}/cfgtest.cxx",
|
||||||
"_TARGET" => "#{@work_dir}/cfgtest.o",
|
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
||||||
"_DEPFILE" => "#{@work_dir}/cfgtest.mf",
|
|
||||||
}
|
}
|
||||||
status = 1
|
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
||||||
check_cpppath.each do |cpppath|
|
|
||||||
env = BasicEnvironment.new
|
|
||||||
if cpppath
|
|
||||||
env["CPPPATH"] += Array(cpppath)
|
|
||||||
end
|
|
||||||
command = env.build_command("${CXXCMD}", vars)
|
|
||||||
_, _, status = log_and_test_command(command)
|
_, _, status = log_and_test_command(command)
|
||||||
if status == 0
|
common_config_checks(status, options)
|
||||||
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
|
||||||
@@ -212,30 +153,15 @@ module Rscons
|
|||||||
vars = {
|
vars = {
|
||||||
"LD" => "${DC}",
|
"LD" => "${DC}",
|
||||||
"_SOURCES" => "#{@work_dir}/cfgtest.d",
|
"_SOURCES" => "#{@work_dir}/cfgtest.d",
|
||||||
"_TARGET" => "#{@work_dir}/cfgtest.o",
|
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
||||||
"_DEPFILE" => "#{@work_dir}/cfgtest.mf",
|
|
||||||
}
|
}
|
||||||
status = 1
|
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
||||||
check_d_import_path.each do |d_import_path|
|
|
||||||
env = BasicEnvironment.new
|
|
||||||
if d_import_path
|
|
||||||
env["D_IMPORT_PATH"] += Array(d_import_path)
|
|
||||||
end
|
|
||||||
command = env.build_command("${DCCMD}", vars)
|
|
||||||
_, _, status = log_and_test_command(command)
|
_, _, status = log_and_test_command(command)
|
||||||
if status == 0
|
common_config_checks(status, options)
|
||||||
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
|
||||||
@@ -250,150 +176,19 @@ module Rscons
|
|||||||
"_SOURCES" => "#{@work_dir}/cfgtest.c",
|
"_SOURCES" => "#{@work_dir}/cfgtest.c",
|
||||||
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
||||||
}
|
}
|
||||||
status = 1
|
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
||||||
check_libpath.each do |libpath|
|
|
||||||
env = BasicEnvironment.new
|
|
||||||
if libpath
|
|
||||||
env["LIBPATH"] += Array(libpath)
|
|
||||||
end
|
|
||||||
command = env.build_command("${LDCMD}", vars)
|
|
||||||
_, _, status = log_and_test_command(command)
|
_, _, status = log_and_test_command(command)
|
||||||
if status == 0
|
|
||||||
if libpath
|
|
||||||
store_append({"LIBPATH" => Array(libpath)}, options)
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if status == 0
|
if status == 0
|
||||||
store_append({"LIBS" => [lib]}, options)
|
store_append({"LIBS" => [lib]}, options)
|
||||||
end
|
end
|
||||||
complete(status, options)
|
common_config_checks(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)
|
||||||
complete(path ? 0 : 1, options.merge(success_message: path))
|
common_config_checks(path ? 0 : 1, options.merge(success_message: path))
|
||||||
end
|
|
||||||
|
|
||||||
# Execute a test command and log the result.
|
|
||||||
#
|
|
||||||
# @param command [Array<String>]
|
|
||||||
# Command to execute.
|
|
||||||
# @param options [Hash]
|
|
||||||
# Optional arguments.
|
|
||||||
# @option options [String] :stdin
|
|
||||||
# Data to send to standard input stream of the executed command.
|
|
||||||
#
|
|
||||||
# @return [String, String, Process::Status]
|
|
||||||
# stdout, stderr, status
|
|
||||||
def log_and_test_command(command, options = {})
|
|
||||||
begin
|
|
||||||
@log_fh.puts("Command: #{command.join(" ")}")
|
|
||||||
stdout, stderr, status = Open3.capture3(*command, stdin_data: options[:stdin])
|
|
||||||
@log_fh.puts("Exit status: #{status.to_i}")
|
|
||||||
@log_fh.write(stdout)
|
|
||||||
@log_fh.write(stderr)
|
|
||||||
[stdout, stderr, status]
|
|
||||||
rescue Errno::ENOENT
|
|
||||||
["", "", 127]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Store construction variables for merging into the Cache.
|
|
||||||
#
|
|
||||||
# @param vars [Hash]
|
|
||||||
# Hash containing the variables to merge.
|
|
||||||
# @param options [Hash]
|
|
||||||
# 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 = {})
|
|
||||||
store_vars = store_common(options)
|
|
||||||
store_vars["merge"] ||= {}
|
|
||||||
vars.each_pair do |key, value|
|
|
||||||
store_vars["merge"][key] = value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Store construction variables for appending into the Cache.
|
|
||||||
#
|
|
||||||
# @param vars [Hash]
|
|
||||||
# Hash containing the variables to append.
|
|
||||||
# @param options [Hash]
|
|
||||||
# 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 = {})
|
|
||||||
store_vars = store_common(options)
|
|
||||||
store_vars["append"] ||= {}
|
|
||||||
vars.each_pair do |key, value|
|
|
||||||
if store_vars["append"][key].is_a?(Array) and value.is_a?(Array)
|
|
||||||
store_vars["append"][key] += value
|
|
||||||
else
|
|
||||||
store_vars["append"][key] = value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Store flags to be parsed into the Cache.
|
|
||||||
#
|
|
||||||
# @param flags [String]
|
|
||||||
# String containing the flags to parse.
|
|
||||||
# @param options [Hash]
|
|
||||||
# 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 = {})
|
|
||||||
store_vars = store_common(options)
|
|
||||||
store_vars["parse"] ||= []
|
|
||||||
store_vars["parse"] << flags
|
|
||||||
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
|
|
||||||
if should_fail
|
|
||||||
Ansi.write($stdout, :red, "#{fail_message}\n")
|
|
||||||
raise ConfigureFailure.new
|
|
||||||
else
|
|
||||||
Ansi.write($stdout, :yellow, "#{fail_message}\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -486,12 +281,7 @@ module Rscons
|
|||||||
"DC" => dc,
|
"DC" => dc,
|
||||||
"DCCMD" => env["DCCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
|
"DCCMD" => env["DCCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
|
||||||
"LDCMD" => env["LDCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
|
"LDCMD" => env["LDCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
|
||||||
"DDEPGEN" => ["-deps=${_DEPFILE}"],
|
|
||||||
}
|
}
|
||||||
if RUBY_PLATFORM =~ /mingw/
|
|
||||||
# ldc2 on Windows expect an object file suffix of .obj.
|
|
||||||
merge["OBJSUFFIX"] = %w[.obj]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
_, _, status = log_and_test_command(command)
|
_, _, status = log_and_test_command(command)
|
||||||
if status == 0
|
if status == 0
|
||||||
@@ -504,6 +294,64 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Execute a test command and log the result.
|
||||||
|
def log_and_test_command(command)
|
||||||
|
begin
|
||||||
|
@log_fh.puts("Command: #{command.join(" ")}")
|
||||||
|
stdout, stderr, status = Open3.capture3(*command)
|
||||||
|
@log_fh.puts("Exit status: #{status.to_i}")
|
||||||
|
@log_fh.write(stdout)
|
||||||
|
@log_fh.write(stderr)
|
||||||
|
[stdout, stderr, status]
|
||||||
|
rescue Errno::ENOENT
|
||||||
|
["", "", 127]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Store construction variables for merging into the Cache.
|
||||||
|
#
|
||||||
|
# @param vars [Hash]
|
||||||
|
# Hash containing the variables to merge.
|
||||||
|
# @param options [Hash]
|
||||||
|
# Options.
|
||||||
|
def store_merge(vars, options = {})
|
||||||
|
store_vars = store_common(options)
|
||||||
|
store_vars["merge"] ||= {}
|
||||||
|
vars.each_pair do |key, value|
|
||||||
|
store_vars["merge"][key] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Store construction variables for appending into the Cache.
|
||||||
|
#
|
||||||
|
# @param vars [Hash]
|
||||||
|
# Hash containing the variables to append.
|
||||||
|
# @param options [Hash]
|
||||||
|
# Options.
|
||||||
|
def store_append(vars, options = {})
|
||||||
|
store_vars = store_common(options)
|
||||||
|
store_vars["append"] ||= {}
|
||||||
|
vars.each_pair do |key, value|
|
||||||
|
if store_vars["append"][key].is_a?(Array) and value.is_a?(Array)
|
||||||
|
store_vars["append"][key] += value
|
||||||
|
else
|
||||||
|
store_vars["append"][key] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Store flags to be parsed into the Cache.
|
||||||
|
#
|
||||||
|
# @param flags [String]
|
||||||
|
# String containing the flags to parse.
|
||||||
|
# @param options [Hash]
|
||||||
|
# Options.
|
||||||
|
def store_parse(flags, options = {})
|
||||||
|
store_vars = store_common(options)
|
||||||
|
store_vars["parse"] ||= []
|
||||||
|
store_vars["parse"] << flags
|
||||||
|
end
|
||||||
|
|
||||||
# Common functionality for all store methods.
|
# Common functionality for all store methods.
|
||||||
#
|
#
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
@@ -527,5 +375,34 @@ 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
|
||||||
+50
-52
@@ -59,9 +59,6 @@ module Rscons
|
|||||||
# :command, :short, or :off (default :short)
|
# :command, :short, or :off (default :short)
|
||||||
# @option options [Boolean] :exclude_builders
|
# @option options [Boolean] :exclude_builders
|
||||||
# Whether to omit adding default builders (default false)
|
# Whether to omit adding default builders (default false)
|
||||||
# @option options [String, 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.
|
||||||
@@ -75,8 +72,7 @@ module Rscons
|
|||||||
# Hash of Thread object => {Command} or {Builder}.
|
# Hash of Thread object => {Command} or {Builder}.
|
||||||
@threads = {}
|
@threads = {}
|
||||||
@registered_build_dependencies = {}
|
@registered_build_dependencies = {}
|
||||||
# Set of side-effect files that have not yet been built.
|
@side_effects = {}
|
||||||
@side_effects = Set.new
|
|
||||||
@builder_sets = []
|
@builder_sets = []
|
||||||
@build_targets = {}
|
@build_targets = {}
|
||||||
@user_deps = {}
|
@user_deps = {}
|
||||||
@@ -169,6 +165,8 @@ module Rscons
|
|||||||
# Create a new {Builders::SimpleBuilder} instance and add it to the
|
# Create a new {Builders::SimpleBuilder} instance and add it to the
|
||||||
# environment.
|
# environment.
|
||||||
#
|
#
|
||||||
|
# @since 1.8.0
|
||||||
|
#
|
||||||
# @param name [String,Symbol]
|
# @param name [String,Symbol]
|
||||||
# The name of the builder to add.
|
# The name of the builder to add.
|
||||||
#
|
#
|
||||||
@@ -218,6 +216,8 @@ module Rscons
|
|||||||
# build operation succeeded. Post-build hooks can register new build
|
# build operation succeeded. Post-build hooks can register new build
|
||||||
# targets.
|
# targets.
|
||||||
#
|
#
|
||||||
|
# @since 1.7.0
|
||||||
|
#
|
||||||
# @yield [build_op]
|
# @yield [build_op]
|
||||||
# Invoke the given block with the current build operation.
|
# Invoke the given block with the current build operation.
|
||||||
# @yieldparam build_op [Hash]
|
# @yieldparam build_op [Hash]
|
||||||
@@ -261,7 +261,6 @@ module Rscons
|
|||||||
#
|
#
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def process
|
def process
|
||||||
Cache.instance.clear_checksum_cache!
|
|
||||||
@process_failures = []
|
@process_failures = []
|
||||||
@process_blocking_wait = false
|
@process_blocking_wait = false
|
||||||
@process_commands_waiting_to_run = []
|
@process_commands_waiting_to_run = []
|
||||||
@@ -287,7 +286,7 @@ module Rscons
|
|||||||
unless @process_failures.empty?
|
unless @process_failures.empty?
|
||||||
msg = @process_failures.join("\n")
|
msg = @process_failures.join("\n")
|
||||||
if Cache.instance["failed_commands"].size > 0
|
if Cache.instance["failed_commands"].size > 0
|
||||||
msg += "\nUse -F to view the failed command log from the previous build operation"
|
msg += "\nRun `#{$0} -F` to see the failed command(s)."
|
||||||
end
|
end
|
||||||
raise BuildError.new(msg)
|
raise BuildError.new(msg)
|
||||||
end
|
end
|
||||||
@@ -375,6 +374,8 @@ module Rscons
|
|||||||
# described:
|
# described:
|
||||||
# env.build_after("program.o", "gen.c")
|
# env.build_after("program.o", "gen.c")
|
||||||
#
|
#
|
||||||
|
# @since 1.10.0
|
||||||
|
#
|
||||||
# @param targets [String, Array<String>]
|
# @param targets [String, Array<String>]
|
||||||
# Target files to wait to build until the prerequisites are finished
|
# Target files to wait to build until the prerequisites are finished
|
||||||
# building.
|
# building.
|
||||||
@@ -401,6 +402,8 @@ module Rscons
|
|||||||
# Manually record the given side effect file(s) as being produced when the
|
# Manually record the given side effect file(s) as being produced when the
|
||||||
# named target is produced.
|
# named target is produced.
|
||||||
#
|
#
|
||||||
|
# @since 1.13.0
|
||||||
|
#
|
||||||
# @param target [String]
|
# @param target [String]
|
||||||
# Target of a build operation.
|
# Target of a build operation.
|
||||||
# @param side_effects [Array<String>]
|
# @param side_effects [Array<String>]
|
||||||
@@ -409,25 +412,11 @@ module Rscons
|
|||||||
# @return [void]
|
# @return [void]
|
||||||
def produces(target, *side_effects)
|
def produces(target, *side_effects)
|
||||||
target = expand_path(expand_varref(target))
|
target = expand_path(expand_varref(target))
|
||||||
@builder_sets.reverse.each do |builder_set|
|
side_effects = Array(side_effects).map do |side_effect|
|
||||||
if builders = builder_set[target]
|
expand_path(expand_varref(side_effect))
|
||||||
builders.last.produces(*side_effects)
|
end.flatten
|
||||||
return
|
@side_effects[target] ||= []
|
||||||
end
|
@side_effects[target] += side_effects
|
||||||
end
|
|
||||||
raise "Could not find a registered build target #{target.inspect}"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Register a side effect file.
|
|
||||||
#
|
|
||||||
# This is an internally used method.
|
|
||||||
#
|
|
||||||
# @api private
|
|
||||||
#
|
|
||||||
# @param side_effect [String]
|
|
||||||
# Side effect fiel name.
|
|
||||||
def register_side_effect(side_effect)
|
|
||||||
@side_effects << side_effect
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return the list of user dependencies for a given target.
|
# Return the list of user dependencies for a given target.
|
||||||
@@ -490,6 +479,29 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Execute a command using the system shell.
|
||||||
|
#
|
||||||
|
# The shell is automatically determined but can be overridden by the SHELL
|
||||||
|
# construction variable. If the SHELL construction variable is specified,
|
||||||
|
# the flag to pass to the shell is automatically dtermined but can be
|
||||||
|
# overridden by the SHELLFLAG construction variable.
|
||||||
|
#
|
||||||
|
# @param command [String] Command to execute.
|
||||||
|
#
|
||||||
|
# @return [String] The command's standard output.
|
||||||
|
def shell(command)
|
||||||
|
shell_cmd =
|
||||||
|
if self["SHELL"]
|
||||||
|
flag = self["SHELLFLAG"] || (self["SHELL"] == "cmd" ? "/c" : "-c")
|
||||||
|
[self["SHELL"], flag]
|
||||||
|
else
|
||||||
|
Rscons.get_system_shell
|
||||||
|
end
|
||||||
|
IO.popen([*shell_cmd, command]) do |io|
|
||||||
|
io.read
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Print the builder run message, depending on the Environment's echo mode.
|
# Print the builder run message, depending on the Environment's echo mode.
|
||||||
#
|
#
|
||||||
# @param builder [Builder]
|
# @param builder [Builder]
|
||||||
@@ -514,12 +526,7 @@ module Rscons
|
|||||||
when :short
|
when :short
|
||||||
message = short_description if short_description
|
message = short_description if short_description
|
||||||
end
|
end
|
||||||
if message
|
Ansi.write($stdout, :cyan, message, :reset, "\n") if message
|
||||||
total_build_steps = Rscons.application.get_total_build_steps.to_s
|
|
||||||
this_build_step = sprintf("%#{total_build_steps.size}d", builder.build_step)
|
|
||||||
progress = "[#{this_build_step}/#{total_build_steps}]"
|
|
||||||
Ansi.write($stdout, *Util.colorize_markup("#{progress} #{message}"), "\n")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get the Builder for a target.
|
# Get the Builder for a target.
|
||||||
@@ -540,16 +547,6 @@ module Rscons
|
|||||||
@builder_sets << build_builder_set
|
@builder_sets << build_builder_set
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get the number of build steps remaining.
|
|
||||||
#
|
|
||||||
# @return [Integer]
|
|
||||||
# The number of build steps remaining.
|
|
||||||
def build_steps_remaining
|
|
||||||
@builder_sets.reduce(0) do |result, builder_set|
|
|
||||||
result + builder_set.build_steps_remaining
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Build a BuilderSet.
|
# Build a BuilderSet.
|
||||||
@@ -567,9 +564,9 @@ module Rscons
|
|||||||
#
|
#
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def run_builder(builder)
|
def run_builder(builder)
|
||||||
unless builder.nop?
|
# TODO: have Cache determine when checksums may be invalid based on
|
||||||
builder.build_step ||= Rscons.application.get_next_build_step
|
# file size and/or timestamp.
|
||||||
end
|
Cache.instance.clear_checksum_cache!
|
||||||
case result = builder.run({})
|
case result = builder.run({})
|
||||||
when Array
|
when Array
|
||||||
result.each do |waititem|
|
result.each do |waititem|
|
||||||
@@ -591,9 +588,8 @@ module Rscons
|
|||||||
when true
|
when true
|
||||||
# Register side-effect files as build targets so that a Cache
|
# Register side-effect files as build targets so that a Cache
|
||||||
# clean operation will remove them.
|
# clean operation will remove them.
|
||||||
builder.side_effects.each do |side_effect|
|
(@side_effects[builder.target] || []).each do |side_effect_file|
|
||||||
Cache.instance.register_build(side_effect, nil, [], self, side_effect: true)
|
Cache.instance.register_build(side_effect_file, nil, [], self)
|
||||||
@side_effects.delete(side_effect)
|
|
||||||
end
|
end
|
||||||
@build_hooks[:post].each do |build_hook_block|
|
@build_hooks[:post].each do |build_hook_block|
|
||||||
build_hook_block.call(builder)
|
build_hook_block.call(builder)
|
||||||
@@ -638,7 +634,7 @@ module Rscons
|
|||||||
if thread
|
if thread
|
||||||
# We found a completed thread.
|
# We found a completed thread.
|
||||||
process_remove_wait(thread)
|
process_remove_wait(thread)
|
||||||
unblocked_builder = builder_for_thread(thread)
|
builder = builder_for_thread(thread)
|
||||||
completed_command = @threads[thread]
|
completed_command = @threads[thread]
|
||||||
@threads.delete(thread)
|
@threads.delete(thread)
|
||||||
if completed_command.is_a?(Command)
|
if completed_command.is_a?(Command)
|
||||||
@@ -646,7 +642,7 @@ module Rscons
|
|||||||
completed_command.status = thread.value
|
completed_command.status = thread.value
|
||||||
unless completed_command.status
|
unless completed_command.status
|
||||||
Cache.instance["failed_commands"] << completed_command.command
|
Cache.instance["failed_commands"] << completed_command.command
|
||||||
@process_failures << "Failed to build #{unblocked_builder.target}."
|
@process_failures << "Failed to build #{builder.target}."
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -671,14 +667,16 @@ module Rscons
|
|||||||
result << builder_for_thread(thread).target
|
result << builder_for_thread(thread).target
|
||||||
end
|
end
|
||||||
if @builder_sets.size > 0
|
if @builder_sets.size > 0
|
||||||
if builder = @builder_sets[0].get_next_builder_to_run(targets_still_building)
|
builder = @builder_sets[0].get_next_builder_to_run(targets_still_building)
|
||||||
|
end
|
||||||
|
|
||||||
|
if builder
|
||||||
builder.vars = @varset.merge(builder.vars)
|
builder.vars = @varset.merge(builder.vars)
|
||||||
@build_hooks[:pre].each do |build_hook_block|
|
@build_hooks[:pre].each do |build_hook_block|
|
||||||
build_hook_block.call(builder)
|
build_hook_block.call(builder)
|
||||||
end
|
end
|
||||||
return run_builder(builder)
|
return run_builder(builder)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if @threads.size > 0
|
if @threads.size > 0
|
||||||
# A runnable builder was not found but there is a thread running,
|
# A runnable builder was not found but there is a thread running,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ module Rscons
|
|||||||
# The Script class encapsulates the state of a build script.
|
# The Script class encapsulates the state of a build script.
|
||||||
class Script
|
class Script
|
||||||
|
|
||||||
# DSL available to the Rsconscript.
|
|
||||||
class Dsl
|
class Dsl
|
||||||
# Create a Dsl.
|
# Create a Dsl.
|
||||||
def initialize(script)
|
def initialize(script)
|
||||||
@@ -58,7 +57,6 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# DSL available to the 'configure' block.
|
|
||||||
class ConfigureDsl
|
class ConfigureDsl
|
||||||
# Create a ConfigureDsl.
|
# Create a ConfigureDsl.
|
||||||
#
|
#
|
||||||
@@ -83,19 +81,6 @@ 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]
|
||||||
|
|||||||
+3
-55
@@ -1,5 +1,4 @@
|
|||||||
module Rscons
|
module Rscons
|
||||||
# A collection of stand-alone utility methods.
|
|
||||||
module Util
|
module Util
|
||||||
class << self
|
class << self
|
||||||
|
|
||||||
@@ -16,30 +15,6 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Colorize a builder run message.
|
|
||||||
#
|
|
||||||
# @param message [String]
|
|
||||||
# Builder run message.
|
|
||||||
#
|
|
||||||
# @return [Array]
|
|
||||||
# Colorized message with color codes for {Ansi} module.
|
|
||||||
def colorize_markup(message)
|
|
||||||
if message =~ /^(.*?)(<[^>]+>)(.*)$/
|
|
||||||
prefix, code, suffix = $1, $2, $3
|
|
||||||
case code
|
|
||||||
when "<target>"
|
|
||||||
code = :magenta
|
|
||||||
when "<source>"
|
|
||||||
code = :cyan
|
|
||||||
when "<reset>"
|
|
||||||
code = :reset
|
|
||||||
end
|
|
||||||
[prefix, code, *colorize_markup(suffix)].delete_if {|v| v == ""}
|
|
||||||
else
|
|
||||||
[message]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Return a string representation of a command.
|
# Return a string representation of a command.
|
||||||
#
|
#
|
||||||
# @param command [Array<String>]
|
# @param command [Array<String>]
|
||||||
@@ -120,27 +95,6 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Format an elapsed time in human-readable format.
|
|
||||||
#
|
|
||||||
# @return [String]
|
|
||||||
# Elapsed time in human-readable format.
|
|
||||||
def format_elapsed_time(elapsed)
|
|
||||||
hours = (elapsed / (60 * 60)).to_i
|
|
||||||
elapsed -= hours * 60 * 60
|
|
||||||
minutes = (elapsed / 60).to_i
|
|
||||||
elapsed -= minutes * 60
|
|
||||||
seconds = elapsed.ceil
|
|
||||||
result = ""
|
|
||||||
if hours > 0
|
|
||||||
result += "#{hours}h "
|
|
||||||
end
|
|
||||||
if hours > 0 || minutes > 0
|
|
||||||
result += "#{minutes}m "
|
|
||||||
end
|
|
||||||
result += "#{seconds}s"
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
# Make a relative path corresponding to a possibly absolute one.
|
# Make a relative path corresponding to a possibly absolute one.
|
||||||
#
|
#
|
||||||
# @param path [String]
|
# @param path [String]
|
||||||
@@ -160,7 +114,7 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Parse dependencies from a Makefile or ldc2 dependency file.
|
# Parse dependencies from a Makefile.
|
||||||
#
|
#
|
||||||
# This method is used internally by Rscons builders.
|
# This method is used internally by Rscons builders.
|
||||||
#
|
#
|
||||||
@@ -169,7 +123,7 @@ module Rscons
|
|||||||
#
|
#
|
||||||
# @return [Array<String>]
|
# @return [Array<String>]
|
||||||
# Paths of dependency files.
|
# Paths of dependency files.
|
||||||
def parse_dependency_file(mf_fname)
|
def parse_makefile_deps(mf_fname)
|
||||||
deps = []
|
deps = []
|
||||||
buildup = ''
|
buildup = ''
|
||||||
File.read(mf_fname).each_line do |line|
|
File.read(mf_fname).each_line do |line|
|
||||||
@@ -177,11 +131,7 @@ module Rscons
|
|||||||
buildup += ' ' + $1
|
buildup += ' ' + $1
|
||||||
else
|
else
|
||||||
buildup += ' ' + line
|
buildup += ' ' + line
|
||||||
if buildup =~ /^[^:]+\(\S+\)\s*:.*?:[^:]+\((\S+)\)/
|
if buildup =~ /^.*: (.*)$/
|
||||||
# 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
|
||||||
@@ -204,7 +154,6 @@ module Rscons
|
|||||||
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/i
|
||||||
if File.directory?(path_entry)
|
|
||||||
executable = executable.downcase
|
executable = executable.downcase
|
||||||
dir_entries = Dir.entries(path_entry)
|
dir_entries = Dir.entries(path_entry)
|
||||||
dir_entries.find do |entry|
|
dir_entries.find do |entry|
|
||||||
@@ -217,7 +166,6 @@ module Rscons
|
|||||||
return path
|
return path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
else
|
else
|
||||||
path = "#{path_entry}/#{executable}"
|
path = "#{path_entry}/#{executable}"
|
||||||
return path if is_executable[path]
|
return path if is_executable[path]
|
||||||
|
|||||||
+23
-50
@@ -11,13 +11,11 @@ module Rscons
|
|||||||
append(vars)
|
append(vars)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Access the value of a variable.
|
# Access the value of variable.
|
||||||
#
|
#
|
||||||
# @param key [String, Symbol]
|
# @param key [String, Symbol] The variable name.
|
||||||
# The variable name.
|
|
||||||
#
|
#
|
||||||
# @return [Object]
|
# @return [Object] The variable's value.
|
||||||
# The variable's value.
|
|
||||||
def [](key)
|
def [](key)
|
||||||
if @my_vars.include?(key)
|
if @my_vars.include?(key)
|
||||||
@my_vars[key]
|
@my_vars[key]
|
||||||
@@ -32,38 +30,11 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Access the value of a variable.
|
|
||||||
#
|
|
||||||
# This method is similar to #[] but does not make a copy-on-access copy of
|
|
||||||
# the variable accessed. This means that the returned value is NOT safe to
|
|
||||||
# be modified by the caller. Thus the caller must guarantee that it does
|
|
||||||
# not modify the returned value.
|
|
||||||
#
|
|
||||||
# @param key [String, Symbol]
|
|
||||||
# The variable name.
|
|
||||||
#
|
|
||||||
# @return [Object]
|
|
||||||
# The variable's value.
|
|
||||||
def get_var(key)
|
|
||||||
if @my_vars.include?(key)
|
|
||||||
@my_vars[key]
|
|
||||||
else
|
|
||||||
@coa_vars.each do |coa_vars|
|
|
||||||
if coa_vars.include?(key)
|
|
||||||
return coa_vars[key]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Assign a value to a variable.
|
# Assign a value to a variable.
|
||||||
#
|
#
|
||||||
# @param key [String, Symbol]
|
# @param key [String, Symbol] The variable name.
|
||||||
# The variable name.
|
|
||||||
#
|
#
|
||||||
# @param val [Object]
|
# @param val [Object] The value to set.
|
||||||
# The value to set.
|
|
||||||
def []=(key, val)
|
def []=(key, val)
|
||||||
@my_vars[key] = val
|
@my_vars[key] = val
|
||||||
end
|
end
|
||||||
@@ -124,27 +95,29 @@ module Rscons
|
|||||||
# Expanded value with "$!{var}" variable references replaced.
|
# Expanded value with "$!{var}" variable references replaced.
|
||||||
def expand_varref(varref, lambda_args)
|
def expand_varref(varref, lambda_args)
|
||||||
case varref
|
case varref
|
||||||
|
when Symbol, true, false, nil
|
||||||
|
varref
|
||||||
when String
|
when String
|
||||||
if varref =~ /^(.*)\$\{([^}]+)\}(.*)$/
|
if varref =~ /^(.*)\$\{([^}]+)\}(.*)$/
|
||||||
prefix, varname, suffix = $1, $2, $3
|
prefix, varname, suffix = $1, $2, $3
|
||||||
prefix = expand_varref(prefix, lambda_args) unless prefix.empty?
|
prefix = expand_varref(prefix, lambda_args) unless prefix.empty?
|
||||||
varval = expand_varref(get_var(varname), lambda_args)
|
varval = expand_varref(self[varname], lambda_args)
|
||||||
# suffix needs no expansion since the regex matches the last occurence
|
# suffix needs no expansion since the regex matches the last occurence
|
||||||
case varval
|
case varval
|
||||||
|
when Symbol, true, false, nil, String
|
||||||
|
if prefix.is_a?(Array)
|
||||||
|
prefix.map {|p| "#{p}#{varval}#{suffix}"}
|
||||||
|
else
|
||||||
|
"#{prefix}#{varval}#{suffix}"
|
||||||
|
end
|
||||||
when Array
|
when Array
|
||||||
if prefix.is_a?(Array)
|
if prefix.is_a?(Array)
|
||||||
varval.map {|vv| prefix.map {|p| "#{p}#{vv}#{suffix}"}}.flatten
|
varval.map {|vv| prefix.map {|p| "#{p}#{vv}#{suffix}"}}.flatten
|
||||||
else
|
else
|
||||||
varval.map {|vv| "#{prefix}#{vv}#{suffix}"}
|
varval.map {|vv| "#{prefix}#{vv}#{suffix}"}
|
||||||
end
|
end
|
||||||
when String, Symbol, true, false, nil
|
|
||||||
if prefix.is_a?(Array)
|
|
||||||
prefix.map {|p| "#{p}#{varval}#{suffix}"}
|
|
||||||
else
|
else
|
||||||
"#{prefix}#{varval}#{suffix}"
|
raise "Unknown construction variable type: #{varval.class} (from #{varname.inspect} => #{self[varname].inspect})"
|
||||||
end
|
|
||||||
else
|
|
||||||
raise "Unknown construction variable type: #{varval.class} (from #{varname.inspect} => #{get_var(varname).inspect})"
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
varref
|
varref
|
||||||
@@ -153,8 +126,6 @@ module Rscons
|
|||||||
varref.map do |ent|
|
varref.map do |ent|
|
||||||
expand_varref(ent, lambda_args)
|
expand_varref(ent, lambda_args)
|
||||||
end.flatten
|
end.flatten
|
||||||
when Symbol, true, false, nil
|
|
||||||
varref
|
|
||||||
when Proc
|
when Proc
|
||||||
expand_varref(varref[*lambda_args], lambda_args)
|
expand_varref(varref[*lambda_args], lambda_args)
|
||||||
else
|
else
|
||||||
@@ -164,6 +135,8 @@ module Rscons
|
|||||||
|
|
||||||
# Return a Hash containing all variables in the VarSet.
|
# Return a Hash containing all variables in the VarSet.
|
||||||
#
|
#
|
||||||
|
# @since 1.8.0
|
||||||
|
#
|
||||||
# This method is not terribly efficient. It is intended to be used only by
|
# This method is not terribly efficient. It is intended to be used only by
|
||||||
# debugging code to dump out a VarSet's variables.
|
# debugging code to dump out a VarSet's variables.
|
||||||
#
|
#
|
||||||
@@ -221,16 +194,16 @@ module Rscons
|
|||||||
#
|
#
|
||||||
# @return [Object] Deep copied value.
|
# @return [Object] Deep copied value.
|
||||||
def deep_dup(obj)
|
def deep_dup(obj)
|
||||||
case obj
|
obj_class = obj.class
|
||||||
when String
|
if obj_class == Hash
|
||||||
obj.dup
|
|
||||||
when Array
|
|
||||||
obj.map { |v| deep_dup(v) }
|
|
||||||
when Hash
|
|
||||||
obj.reduce({}) do |result, (k, v)|
|
obj.reduce({}) do |result, (k, v)|
|
||||||
result[k] = deep_dup(v)
|
result[k] = deep_dup(v)
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
elsif obj_class == Array
|
||||||
|
obj.map { |v| deep_dup(v) }
|
||||||
|
elsif obj_class == String
|
||||||
|
obj.dup
|
||||||
else
|
else
|
||||||
obj
|
obj
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module Rscons
|
module Rscons
|
||||||
# Project version.
|
# Project version.
|
||||||
VERSION = "2.0.1"
|
VERSION = "1.16.0"
|
||||||
end
|
end
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Rscons User Guide<%= subpage_title %> - Version <%= Rscons::VERSION %></title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
background-color: #CCC;
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
#body-table {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
#body-left-border {
|
|
||||||
width: 10px;
|
|
||||||
background-image: linear-gradient(to right, #CCC, #000, #FFF);
|
|
||||||
}
|
|
||||||
#body-right-border {
|
|
||||||
width: 10px;
|
|
||||||
background-image: linear-gradient(to right, #FFF, #000, #CCC);
|
|
||||||
}
|
|
||||||
#body-center {
|
|
||||||
background-color: #FFF;
|
|
||||||
width: 120ex;
|
|
||||||
padding: 1ex;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.separator {
|
|
||||||
height: 2em;
|
|
||||||
}
|
|
||||||
.img_block_center {
|
|
||||||
display: block;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
.page_nav {
|
|
||||||
width: 100%;
|
|
||||||
table-layout: fixed;
|
|
||||||
}
|
|
||||||
.page_nav_toc {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.page_nav_next {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.code {
|
|
||||||
padding-left: 2ex;
|
|
||||||
width: 116ex;
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
.ruby_code .normal {}
|
|
||||||
.ruby_code .comment { color: #005; font-style: italic; }
|
|
||||||
.ruby_code .keyword { color: #A00; font-weight: bold; }
|
|
||||||
.ruby_code .method { color: #077; }
|
|
||||||
.ruby_code .class { color: #074; }
|
|
||||||
.ruby_code .module { color: #050; }
|
|
||||||
.ruby_code .punct { color: #447; font-weight: bold; }
|
|
||||||
.ruby_code .symbol { color: #099; }
|
|
||||||
.ruby_code .string { color: #090; }
|
|
||||||
.ruby_code .char { color: #F07; }
|
|
||||||
.ruby_code .ident { color: #004; }
|
|
||||||
.ruby_code .constant { color: #07F; }
|
|
||||||
.ruby_code .regex { color: #B66; }
|
|
||||||
.ruby_code .number { color: #D55; }
|
|
||||||
.ruby_code .attribute { color: #377; }
|
|
||||||
.ruby_code .global { color: #3B7; }
|
|
||||||
.ruby_code .expr { color: #227; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table id="body-table">
|
|
||||||
<tr>
|
|
||||||
<td id="body-left-border"></td>
|
|
||||||
<td id="body-center"><%= content %></td>
|
|
||||||
<td id="body-right-border"></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
+10
-9
@@ -1,13 +1,17 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
require "fileutils"
|
require "fileutils"
|
||||||
require "digest/md5"
|
|
||||||
|
|
||||||
if File.read("lib/rscons/version.rb") =~ /VERSION = "(.+)"/
|
if File.read("lib/rscons/version.rb") =~ /VERSION = "(.+)"/
|
||||||
VERSION = $1
|
VERSION = $1
|
||||||
else
|
else
|
||||||
raise "Could not determine version."
|
raise "Could not determine version."
|
||||||
end
|
end
|
||||||
|
if `git show | head -n 1` =~ /commit\s+([0-9a-f]{7})/i
|
||||||
|
GIT = $1
|
||||||
|
else
|
||||||
|
raise "Could not determine git revision."
|
||||||
|
end
|
||||||
PROG_NAME = "rscons"
|
PROG_NAME = "rscons"
|
||||||
START_FILE = "bin/#{PROG_NAME}"
|
START_FILE = "bin/#{PROG_NAME}"
|
||||||
LIB_DIR = "lib"
|
LIB_DIR = "lib"
|
||||||
@@ -59,22 +63,19 @@ combined_file.each do |line|
|
|||||||
end
|
end
|
||||||
|
|
||||||
require "zlib"
|
require "zlib"
|
||||||
require "base64"
|
|
||||||
compressed_script = Zlib::Deflate.deflate(stripped_comments.join)
|
compressed_script = Zlib::Deflate.deflate(stripped_comments.join)
|
||||||
encoded_compressed_script = Base64.encode64(compressed_script).gsub("\n", "")
|
escaped_compressed_script = compressed_script.gsub("#", "#1").gsub("\n", "#2").gsub("\r", "#3").gsub("\0", "#4")
|
||||||
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|
|
||||||
fh.write(<<EOF)
|
fh.write(<<EOF)
|
||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
script = File.join(File.dirname(__FILE__), ".rscons-#{VERSION}-#{hash}.rb")
|
script = ".rscons-#{VERSION}-#{GIT}.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)
|
||||||
@@ -87,6 +88,6 @@ load script
|
|||||||
if __FILE__ == $0
|
if __FILE__ == $0
|
||||||
Rscons::Cli.run(ARGV)
|
Rscons::Cli.run(ARGV)
|
||||||
end
|
end
|
||||||
#==>#{encoded_compressed_script}
|
#==>#{escaped_compressed_script}
|
||||||
EOF
|
EOF
|
||||||
end
|
end
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
require "erb"
|
|
||||||
require "fileutils"
|
|
||||||
require "redcarpet"
|
|
||||||
require "syntax"
|
|
||||||
require "syntax/convertors/html"
|
|
||||||
require "rscons/version"
|
|
||||||
|
|
||||||
def load_file(file_name)
|
|
||||||
contents = File.read(file_name)
|
|
||||||
contents.gsub(/\$\{include (.*?)\}/) do |match|
|
|
||||||
include_file_name = $1
|
|
||||||
File.read(include_file_name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Generator
|
|
||||||
class Section
|
|
||||||
attr_reader :number
|
|
||||||
attr_reader :title
|
|
||||||
attr_reader :page
|
|
||||||
attr_reader :contents
|
|
||||||
attr_reader :anchor
|
|
||||||
def initialize(number, title, page, anchor)
|
|
||||||
@number = number
|
|
||||||
@title = title.gsub(/[`]/, "")
|
|
||||||
@page = page
|
|
||||||
@anchor = anchor
|
|
||||||
@contents = ""
|
|
||||||
end
|
|
||||||
def append(contents)
|
|
||||||
@contents += contents
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Page
|
|
||||||
attr_reader :name
|
|
||||||
attr_reader :title
|
|
||||||
attr_accessor :contents
|
|
||||||
def initialize(name, title, contents = "")
|
|
||||||
@name = name
|
|
||||||
@title = title
|
|
||||||
@contents = contents
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(input, output_file, multi_page)
|
|
||||||
current_page =
|
|
||||||
if multi_page
|
|
||||||
nil
|
|
||||||
else
|
|
||||||
File.basename(output_file).sub(/\.html$/, "")
|
|
||||||
end
|
|
||||||
@sections = []
|
|
||||||
@current_section_number = [0]
|
|
||||||
@lines = input.lines
|
|
||||||
while @lines.size > 0
|
|
||||||
line = @lines.slice!(0)
|
|
||||||
if line =~ /^```(.*)$/
|
|
||||||
@sections.last.append(gather_code_section($1))
|
|
||||||
elsif line.chomp == "${remove}"
|
|
||||||
remove_section
|
|
||||||
elsif line =~ /^(#+)(>)?\s*(.*)$/
|
|
||||||
level_text, new_page_text, title_text = $1, $2, $3
|
|
||||||
level = $1.size
|
|
||||||
new_page = !new_page_text.nil?
|
|
||||||
section_number = get_next_section_number(level)
|
|
||||||
anchor = make_anchor(section_number, title_text)
|
|
||||||
if multi_page and (new_page or current_page.nil?)
|
|
||||||
current_page = anchor
|
|
||||||
end
|
|
||||||
@sections << Section.new(section_number, title_text, current_page, anchor)
|
|
||||||
@sections.last.append("#{level_text} #{section_number} #{title_text}")
|
|
||||||
elsif @sections.size > 0
|
|
||||||
@sections.last.append(line)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
renderer = Redcarpet::Render::HTML.new
|
|
||||||
@markdown_renderer = Redcarpet::Markdown.new(renderer)
|
|
||||||
changelog = @markdown_renderer.render(File.read("CHANGELOG.md"))
|
|
||||||
|
|
||||||
@pages = [Page.new("toc", "Table of Contents", render_toc)]
|
|
||||||
@sections.each do |section|
|
|
||||||
unless @pages.last.name == section.page
|
|
||||||
@pages << Page.new(section.page, "#{section.number} #{section.title}")
|
|
||||||
end
|
|
||||||
@pages.last.contents += render_section(section)
|
|
||||||
end
|
|
||||||
|
|
||||||
@pages.each do |page|
|
|
||||||
page.contents.gsub!("${changelog}", changelog)
|
|
||||||
page.contents.gsub!(%r{\$\{#(.+?)\}}) do |match|
|
|
||||||
section_name = $1
|
|
||||||
href = get_link_to_section(section_name)
|
|
||||||
%[<a href="#{href}">#{section_name}</a>]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
template = File.read("rb/assets/user_guide.html.erb")
|
|
||||||
erb = ERB.new(template, nil, "<>")
|
|
||||||
|
|
||||||
if multi_page
|
|
||||||
@pages.each_with_index do |page, page_index|
|
|
||||||
subpage_title = " - #{page.title}"
|
|
||||||
page_nav_bar = render_page_nav_bar(page_index)
|
|
||||||
content = page_nav_bar + separator + page.contents + separator + page_nav_bar
|
|
||||||
html_result = erb.result(binding.clone)
|
|
||||||
File.open(File.join(output_file, "#{page.name}.html"), "w") do |fh|
|
|
||||||
fh.write(html_result)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
subpage_title = ""
|
|
||||||
content = @pages.reduce("") do |result, page|
|
|
||||||
result + page.contents
|
|
||||||
end
|
|
||||||
html_result = erb.result(binding.clone)
|
|
||||||
File.open(output_file, "w") do |fh|
|
|
||||||
fh.write(html_result)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def separator
|
|
||||||
%[<div class="separator"></div>]
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_page_nav_bar(page_index)
|
|
||||||
page_nav_prev =
|
|
||||||
if page_index > 1
|
|
||||||
%[<a href="#{@pages[page_index - 1].name}.html">« Prev<br/>#{@pages[page_index - 1].title}</a>]
|
|
||||||
else
|
|
||||||
""
|
|
||||||
end
|
|
||||||
page_nav_toc =
|
|
||||||
if page_index > 0
|
|
||||||
%[<a href="toc.html">Table of Contents</a>]
|
|
||||||
else
|
|
||||||
""
|
|
||||||
end
|
|
||||||
page_nav_next =
|
|
||||||
if page_index < @pages.size - 1
|
|
||||||
%[<a href="#{@pages[page_index + 1].name}.html">Next »<br/>#{@pages[page_index + 1].title}</a>]
|
|
||||||
else
|
|
||||||
""
|
|
||||||
end
|
|
||||||
%[<table class="page_nav"><tr>] + \
|
|
||||||
%[<td class="page_nav_prev">#{page_nav_prev}</td>] + \
|
|
||||||
%[<td class="page_nav_toc">#{page_nav_toc}</td>] + \
|
|
||||||
%[<td class="page_nav_next">#{page_nav_next}</td>] + \
|
|
||||||
%[</tr></table>]
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_toc
|
|
||||||
toc_content = %[<img class="img_block_center" src="rscons_logo_1000.png" />]
|
|
||||||
toc_content += %[<h1>Table of Contents</h1>\n]
|
|
||||||
@sections.each do |section|
|
|
||||||
indent = section.number.split(".").size - 1
|
|
||||||
toc_content += %[<span style="padding-left: #{4 * indent}ex;">]
|
|
||||||
toc_content += %[<a href="#{section.page}.html##{section.anchor}">#{section.number} #{section.title}</a><br/>\n]
|
|
||||||
toc_content += %[</span>]
|
|
||||||
end
|
|
||||||
toc_content
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_section(section)
|
|
||||||
%[<a name="#{section.anchor}" />] + \
|
|
||||||
@markdown_renderer.render(section.contents)
|
|
||||||
end
|
|
||||||
|
|
||||||
def make_anchor(section_number, section_title)
|
|
||||||
"s" + ("#{section_number} #{section_title}").gsub(/[^a-zA-Z0-9]/, "_")
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_link_to_section(section_name)
|
|
||||||
section = @sections.find do |section|
|
|
||||||
section.title == section_name
|
|
||||||
end
|
|
||||||
raise "Could not find section #{section_name}" unless section
|
|
||||||
"#{section.page}.html##{section.anchor}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def gather_code_section(syntax)
|
|
||||||
code = ""
|
|
||||||
loop do
|
|
||||||
line = @lines.slice!(0)
|
|
||||||
if line =~ /^```/
|
|
||||||
break
|
|
||||||
end
|
|
||||||
code += line
|
|
||||||
end
|
|
||||||
if syntax != ""
|
|
||||||
convertor = Syntax::Convertors::HTML.for_syntax(syntax)
|
|
||||||
%[<div class="code #{syntax}_code">\n#{convertor.convert(code)}\n</div>\n]
|
|
||||||
else
|
|
||||||
%[<div class="code">\n<pre>#{code}</pre>\n</div>\n]
|
|
||||||
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)
|
|
||||||
if @current_section_number.size == level - 1
|
|
||||||
@current_section_number << 1
|
|
||||||
elsif @current_section_number.size >= level
|
|
||||||
@current_section_number[level - 1] += 1
|
|
||||||
@current_section_number.slice!(level, @current_section_number.size)
|
|
||||||
else
|
|
||||||
raise "Section level change from #{@current_section_number.size} to #{level}"
|
|
||||||
end
|
|
||||||
@current_section_number.join(".")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
input = load_file("doc/user_guide.md")
|
|
||||||
FileUtils.rm_rf("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", true)
|
|
||||||
+252
-688
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,30 @@
|
|||||||
|
module Rscons
|
||||||
|
describe Application do
|
||||||
|
|
||||||
|
describe ".clean" do
|
||||||
|
it "removes all build targets and created directories" do
|
||||||
|
cache = "cache"
|
||||||
|
expect(Rscons::Cache).to receive(:instance).and_return(cache)
|
||||||
|
expect(cache).to receive(:targets).and_return(["build/a.out", "build/main.o"])
|
||||||
|
expect(FileUtils).to receive(:rm_f).with("build/a.out")
|
||||||
|
expect(FileUtils).to receive(:rm_f).with("build/main.o")
|
||||||
|
expect(cache).to receive(:directories).and_return(["build/one", "build/one/two", "build", "other"])
|
||||||
|
expect(File).to receive(:directory?).with("build/one/two").and_return(true)
|
||||||
|
expect(Dir).to receive(:entries).with("build/one/two").and_return([".", ".."])
|
||||||
|
expect(Dir).to receive(:rmdir).with("build/one/two")
|
||||||
|
expect(File).to receive(:directory?).with("build/one").and_return(true)
|
||||||
|
expect(Dir).to receive(:entries).with("build/one").and_return([".", ".."])
|
||||||
|
expect(Dir).to receive(:rmdir).with("build/one")
|
||||||
|
expect(File).to receive(:directory?).with("build").and_return(true)
|
||||||
|
expect(Dir).to receive(:entries).with("build").and_return([".", ".."])
|
||||||
|
expect(Dir).to receive(:rmdir).with("build")
|
||||||
|
expect(File).to receive(:directory?).with("other").and_return(true)
|
||||||
|
expect(Dir).to receive(:entries).with("other").and_return([".", "..", "other.file"])
|
||||||
|
expect(cache).to receive(:clear)
|
||||||
|
|
||||||
|
Rscons.application.__send__(:clean)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -13,6 +13,13 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#targets" do
|
||||||
|
it "returns a list of targets that are cached" do
|
||||||
|
cache = {"targets" => {"t1" => {}, "t2" => {}, "t3" => {}}}
|
||||||
|
expect(build_from(cache).targets).to eq ["t1", "t2", "t3"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#mkdir_p" do
|
describe "#mkdir_p" do
|
||||||
it "makes directories and records any created in the cache" do
|
it "makes directories and records any created in the cache" do
|
||||||
_cache = {}
|
_cache = {}
|
||||||
@@ -28,7 +35,7 @@ module Rscons
|
|||||||
expect(FileUtils).to receive(:mkdir_p).with("one/two/four")
|
expect(FileUtils).to receive(:mkdir_p).with("one/two/four")
|
||||||
cache.mkdir_p("one/two/three")
|
cache.mkdir_p("one/two/three")
|
||||||
cache.mkdir_p("one\\two\\four")
|
cache.mkdir_p("one\\two\\four")
|
||||||
expect(cache.directories(false)).to eq ["one/two", "one/two/three", "one/two/four"]
|
expect(cache.directories).to eq ["one/two", "one/two/three", "one/two/four"]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "handles absolute paths" do
|
it "handles absolute paths" do
|
||||||
@@ -38,7 +45,14 @@ module Rscons
|
|||||||
expect(File).to receive(:exists?).with("/one/two").and_return(false)
|
expect(File).to receive(:exists?).with("/one/two").and_return(false)
|
||||||
expect(FileUtils).to receive(:mkdir_p).with("/one/two")
|
expect(FileUtils).to receive(:mkdir_p).with("/one/two")
|
||||||
cache.mkdir_p("/one/two")
|
cache.mkdir_p("/one/two")
|
||||||
expect(cache.directories(false)).to eq ["/one/two"]
|
expect(cache.directories).to eq ["/one/two"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#directories" do
|
||||||
|
it "returns a list of directories that are cached" do
|
||||||
|
_cache = {"directories" => {"dir1" => true, "dir2" => true}}
|
||||||
|
expect(build_from(_cache).directories).to eq ["dir1", "dir2"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -65,5 +79,12 @@ module Rscons
|
|||||||
expect(build_from({}).send(:calculate_checksum, "fname")).to eq "the_checksum"
|
expect(build_from({}).send(:calculate_checksum, "fname")).to eq "the_checksum"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#validate_json_object" do
|
||||||
|
it "raises an error when an unexpected object is passed" do
|
||||||
|
cache = build_from({})
|
||||||
|
expect {cache.__send__(:validate_json_object, :symbol)}.to raise_error /Unexpected cache value/
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -29,12 +29,6 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".colorize_markup" do
|
|
||||||
it "turns a builder message string with markup into an Array for Ansi module" do
|
|
||||||
expect(Util.colorize_markup("[ 1/33] Generating <foo> lexer from <source>parser/lexer.l<reset> => <target>build/e.1/parser/lexer.cc<reset>")).to eq ["[ 1/33] Generating ", "<foo>", " lexer from ", :cyan, "parser/lexer.l", :reset, " => ", :magenta, "build/e.1/parser/lexer.cc", :reset]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ".determine_n_threads" do
|
describe ".determine_n_threads" do
|
||||||
context "when specified by environment variable" do
|
context "when specified by environment variable" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@@ -121,10 +115,7 @@ 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:\\none;C:\\bin;C:\\Windows")
|
expect(ENV).to receive(:[]).with("PATH").and_return("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
|
||||||
@@ -160,20 +151,6 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".format_elapsed_time" do
|
|
||||||
it "includes minutes when hours is nonzero and minutes is zero" do
|
|
||||||
expect(Util.format_elapsed_time(60 * 60 + 4)).to eq "1h 0m 4s"
|
|
||||||
end
|
|
||||||
|
|
||||||
it "only includes minutes and seconds when hours is zero and minutes is nonzero" do
|
|
||||||
expect(Util.format_elapsed_time(3 * 60 + 33)).to eq "3m 33s"
|
|
||||||
end
|
|
||||||
|
|
||||||
it "only includes seconds when hours and minutes are zero" do
|
|
||||||
expect(Util.format_elapsed_time(7.84)).to eq "8s"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ".make_relative_path" do
|
describe ".make_relative_path" do
|
||||||
context "when passed a relative path" do
|
context "when passed a relative path" do
|
||||||
it "returns the path itself" do
|
it "returns the path itself" do
|
||||||
@@ -200,12 +177,12 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".parse_dependency_file" do
|
describe ".parse_makefile_deps" 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_dependency_file('makefile')).to eq ['source.cc']
|
expect(Util.parse_makefile_deps('makefile')).to eq ['source.cc']
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'handles dependencies split across many lines' do
|
it 'handles dependencies split across many lines' do
|
||||||
@@ -214,22 +191,9 @@ module.o: module.c \\
|
|||||||
module.h \\
|
module.h \\
|
||||||
other.h
|
other.h
|
||||||
EOS
|
EOS
|
||||||
expect(Util.parse_dependency_file('makefile')).to eq [
|
expect(Util.parse_makefile_deps('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
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ module Rscons
|
|||||||
expect { v.expand_varref({a: :b}, :lambda_args) }.to raise_error /Unknown construction variable type: Hash/
|
expect { v.expand_varref({a: :b}, :lambda_args) }.to raise_error /Unknown construction variable type: Hash/
|
||||||
end
|
end
|
||||||
it "raises an error when an expanded variable is an unexpected type" do
|
it "raises an error when an expanded variable is an unexpected type" do
|
||||||
expect(v).to receive(:get_var).at_least(1).times.with("bad").and_return("bad_val")
|
expect(v).to receive(:[]).at_least(1).times.with("bad").and_return("bad_val")
|
||||||
expect(v).to receive(:expand_varref).with("bad_val", :lambda_args).and_return({a: :b})
|
expect(v).to receive(:expand_varref).with("bad_val", :lambda_args).and_return({a: :b})
|
||||||
expect(v).to receive(:expand_varref).and_call_original
|
expect(v).to receive(:expand_varref).and_call_original
|
||||||
expect { v.expand_varref("${bad}", :lambda_args) }.to raise_error /Unknown construction variable type: Hash/
|
expect { v.expand_varref("${bad}", :lambda_args) }.to raise_error /Unknown construction variable type: Hash/
|
||||||
|
|||||||
Reference in new issue
Block a user