Compare commits

..
136 Commits
Author SHA1 Message Date
josh 11864eb55b v1.10.0 2017-06-10 00:50:43 -04:00
Michael Metivier 387c40176b Pre-build hooks do not respect modified key values for old-style builders 2017-06-09 19:50:12 -04:00
josh f1b24ee8ba minor formatting: replace missing space 2017-06-08 15:01:30 -04:00
josh ef3150db0f document construction variables and their default values in README.md 2017-06-08 14:58:55 -04:00
josh ed4fb8b681 expand README.md a bit 2017-06-08 14:10:42 -04:00
josh 3a3f6d6d27 add v1.10.0 release notes 2017-06-08 12:02:13 -04:00
josh 20affc0e1d fix SHLD spec for Windows 2017-06-08 12:01:50 -04:00
josh 010607d3b0 Rework builder features to be returned by Builder#features instead of taken into account by Builder#produces? 2017-06-08 11:07:01 -04:00
josh b7f609b7e8 add SHLIBPREFIX 2017-06-07 16:35:20 -04:00
josh 10d4c647b9 add spec for building a shared library using D 2017-06-07 15:22:20 -04:00
josh db2ec82a25 Add more integration tests for SharedLibrary and backwards compatibility 2017-06-07 13:02:51 -04:00
josh aa192d7567 bugfix: Object and SharedObject should respect vars when checking source suffixes 2017-06-07 09:52:11 -04:00
josh ed5d6e9e49 homogenize slashes in Environment#expand_path() 2017-06-07 09:26:13 -04:00
josh 3436dc3a64 Expand target and sources before calling Builder#create_build_target 2017-06-06 16:43:26 -04:00
josh df52a7e0e1 add SharedObject and SharedLibrary builders - close #8 2017-06-06 13:27:38 -04:00
josh 6bd7e6f852 Object builder changes in preparation for adding SharedObject 2017-05-30 16:26:39 -04:00
josh 19a23c2aa9 Create builder features
Pass desired features to Builder#produces?
Allow features to be passed in to Environment#register_builds.
Use features in Environment#get_build_fname to determine build file name.
2017-05-30 15:30:15 -04:00
josh c7e4e1ad9b Always use a build root and default it to "build" 2017-05-30 11:06:32 -04:00
josh 43df46018c Support redirecting standard output using the Command builder - close #28 2017-05-29 12:50:34 -04:00
josh 8cbb9fa30e Place object files for absolute source paths under build_root - close #30 2017-05-29 12:16:46 -04:00
josh 1880e6650e fix PROGSUFFIX handling - close #29 2017-05-29 11:40:01 -04:00
josh d31b4725d2 add LEXSUFFIX, YACCSUFFIX construction variables - close #31 2017-05-29 11:03:01 -04:00
josh 6f242a1c64 Merge branch 'parallelization' - close #23 2017-05-29 10:58:55 -04:00
josh c7943bc2cc ignore .bundle 2017-05-29 10:57:27 -04:00
josh b5826bd7f4 use new Builder#run signature for Command builder 2017-05-25 17:06:34 -04:00
josh 05bbea6fa1 add Environment#build_after 2017-05-25 17:00:21 -04:00
josh 68468b6422 fully parallelize the Command builder 2017-05-25 16:03:05 -04:00
josh 80a80a7cb0 fully parallelize the Preprocess builder 2017-05-25 15:54:33 -04:00
josh 178940cd5d fully parallelize the CFile builder 2017-05-25 15:28:01 -04:00
josh 145d51c825 fully parallelize the Disassemble builder 2017-05-25 14:59:51 -04:00
josh a11fab43cb Update spec task to preserve simplecov coverage info for previous full spec runs when doing a partial spec run 2017-05-24 16:29:17 -04:00
josh 83226e894d add backwards-compatibility test for Builder#standard_build 2017-05-24 16:16:53 -04:00
josh b454208117 fully parallelize the Library builder 2017-05-24 16:10:58 -04:00
josh df420fdf5c use ThreadsWait (only for blocking thread waits) 2017-05-24 16:02:25 -04:00
josh f3bf325c88 add a little more leeway in the multi-threading timing test 2017-05-24 15:58:11 -04:00
josh f815952ab3 add Builder#standard_threaded_build, #standard_finalize
parallelize Program builder command
2017-05-24 15:41:39 -04:00
josh 1af3c5c9a4 pass Builder#run options into Builder#finalize also 2017-05-24 15:13:59 -04:00
josh dce88ece14 pass entire build_operation Hash to Builder#run 2017-05-24 14:32:43 -04:00
josh 2655c119e4 add spec for Environment#find_finished_thread to fully cover 2017-05-23 16:47:00 -04:00
josh 221cde7e5f update run_builder, build_sources integration tests for more coverage 2017-05-23 16:45:21 -04:00
josh adcee373df add integration test for Environment#build_sources 2017-05-23 16:28:13 -04:00
josh e58b8bd109 add integration test for Environment#run_builder 2017-05-23 16:25:03 -04:00
josh 8a1dfb0785 do not catch NameError when looking up Builder#run method 2017-05-23 16:24:45 -04:00
josh d315f86a36 remove unit tests for Environment#run_builder, #build_sources 2017-05-23 16:20:41 -04:00
josh 0d46d616dd change user dependency test to use BuildTarget#depends 2017-05-23 16:09:29 -04:00
josh 032e6d5d0a add some integration tests for the CLI 2017-05-23 16:06:21 -04:00
josh c9946da193 integration tests: only pass -f when a specific rsconsfile is specified 2017-05-23 15:55:28 -04:00
josh 599d10b50f add integration test for overriding PROGSUFFIX 2017-05-23 15:32:55 -04:00
josh 18c6c69871 do not use ThreadsWait to wait for threads; it does not work properly 2017-05-23 15:24:52 -04:00
josh 2ffdf82d9a add multi-threading build test 2017-05-23 14:24:14 -04:00
josh 15e5d15424 Avoid Environment#process race condition
Race condition could have occurred if the last threaded command
was gathered in the non-blocking wait and then a blocking wait was
started because there was no job to run. Do not do a blocking wait
in this case.
2017-05-23 14:12:38 -04:00
josh a99e6e81b2 simplify Environment#process looping 2017-05-23 14:10:45 -04:00
josh 1509c95176 remove Cache.reset! 2017-05-23 14:05:29 -04:00
josh c7bba77581 remove Program builder non-integration specs 2017-05-22 16:57:35 -04:00
josh 957fd8c86d convert Library builder specs to integration tests 2017-05-22 16:54:10 -04:00
josh 7e707e7e3b convert Object builder specs to integration tests 2017-05-22 16:38:57 -04:00
josh 2be738be4f Including trailing newline when printing failed command 2017-05-22 16:26:12 -04:00
josh 7b3bffd329 update some non-integration-test specs 2017-05-22 16:25:49 -04:00
josh 06cb4b7a55 migrate some Cache tests to integration tests 2017-05-22 15:55:18 -04:00
josh bfbbc19728 fix simplecov setup to get coverage for integration build tests 2017-05-22 11:19:55 -04:00
josh 28e56251dd update build_tests_spec to invoke rscons in a subprocess for each test 2017-05-20 15:15:07 -04:00
josh 2d8e08b493 add -j command-line option to set number of threads 2017-05-19 11:38:42 -04:00
josh 5cef9896ac consistently print failed build command if a builder fails 2017-05-19 10:57:30 -04:00
josh 6344692087 update Object builder to support parallelization; update Program and Library builders to register object builds from #setup 2017-05-19 10:49:16 -04:00
josh 267fc7124d process threaded commands until they are all complete 2017-05-17 15:52:34 -04:00
josh e694199f33 delay building targets that depend on builds registered with Environment#register_builds 2017-05-17 15:45:04 -04:00
josh 4ed584701a pass setup_info to the builder's #run method 2017-05-17 13:50:31 -04:00
josh 5de52620e4 JobSet#get_next_job_to_run: take into account targets still building 2017-05-17 10:19:43 -04:00
josh 9cc59a35f0 handle threaded commands in Environment#process 2017-05-17 10:07:15 -04:00
josh ca445f5733 add JobSet#size 2017-05-17 09:36:27 -04:00
josh 7534b29e26 add Environment#wait_for_threaded_commands, use from #run_builder if delayed execution is not allowed 2017-05-17 09:34:19 -04:00
josh 800e7a51a4 add Environment#start_threaded_command 2017-05-17 09:14:42 -04:00
josh 5d36aa74a0 add more fields to ThreadedCommand 2017-05-17 09:07:51 -04:00
josh 01851c2872 refactor into new Environment#command_to_s 2017-05-17 09:04:05 -04:00
josh 5fe55a584e add short description field to ThreadedCommand 2017-05-17 08:49:53 -04:00
josh 9c13634eaf start adding support for threaded commands in Environment#run_builder 2017-05-17 08:47:17 -04:00
josh e4adaab003 add Builder#finalize 2017-05-16 09:18:08 -04:00
josh 6b8fda706d add ThreadedCommand class 2017-05-15 10:57:34 -04:00
josh ef4f9882cd change Builder#run base class method to new signature 2017-05-12 21:08:14 -04:00
josh 7a31039e35 add @since tags for new methods 2017-05-12 21:07:25 -04:00
josh 3e4897c04b store setup_info in the job 2017-05-12 16:30:30 -04:00
josh d46dc2014c update JobSet interface to just take a Hash of job parameters 2017-05-12 16:30:02 -04:00
josh 9cfc0c20b7 call Builder#setup 2017-05-12 16:27:43 -04:00
josh 19a00a7b84 prepare to call new Builder#run interface 2017-05-12 16:25:34 -04:00
josh 9b6d2c5111 add Environment#register_builds 2017-05-12 16:16:25 -04:00
josh 6a0ccad804 add Builder#setup; add new Builder#run signature 2017-05-12 16:16:07 -04:00
josh dab870854a add Rscons.n_threads 2017-05-12 14:38:18 -04:00
josh 695bf84092 expand target and source paths when registering a builder 2017-05-10 15:06:16 -04:00
josh 7cba8c8424 JobSet: target is already stored in job info 2017-05-10 14:57:04 -04:00
josh 551b8fa365 add integration test to verify cache is written if a builder fails 2017-02-16 19:27:18 -05:00
josh 3601359c08 process jobs from the JobSet 2017-02-16 19:27:18 -05:00
josh e1d8dfbab6 add JobSet class 2017-02-16 19:27:18 -05:00
josh c69da1044d update README for v1.9.3 2016-09-30 14:04:58 -04:00
josh f33be07a15 v1.9.3 2016-09-30 14:03:35 -04:00
josh c4c2d5c128 Environment#parse_flags should put -std=XXX flags in CCFLAGS, not CFLAGS 2016-09-30 14:02:30 -04:00
josh 3065dc48ec document passing multiple dependencies to env.depends() 2016-05-02 09:10:14 -04:00
josh 9ca2934695 document explicit dependencies 2016-03-02 13:33:00 -05:00
josh 3af6b6be1b v1.9.2 2016-01-12 10:16:00 -05:00
josh 0442b876a5 allow phony targets in conjunction with a build root 2016-01-12 10:14:10 -05:00
josh bab4641b6e v1.9.1 2015-12-10 15:25:29 -05:00
josh 4698fc41b9 add v1.9.1 release notes 2015-12-10 15:25:16 -05:00
josh 952f423860 use ${INCPREFIX} instead of hard-coded "-I" in Preprocess builder 2015-12-10 15:19:41 -05:00
josh d2da5f7b0d bundle update 2015-12-10 15:18:59 -05:00
josh ab14dc16ed change *SUFFIX defaults to arrays; add various C++ file suffixes 2015-06-15 21:58:37 -04:00
josh aa795eea85 v1.9.0 2015-03-15 20:56:37 -04:00
josh 7dffef6bd0 update README.md 2015-02-15 19:52:33 -05:00
josh dce2114733 document Copy builder class 2015-02-15 18:42:37 -05:00
josh 0bbdda2d41 fix Command builder default short description 2015-02-15 18:41:41 -05:00
josh 3b8910075a use class instance variables instead of class variables 2015-02-15 18:38:09 -05:00
josh 34beda844e reorganize Rscons module class methods 2015-02-15 18:33:00 -05:00
josh 7a04bec2ff support phony targets - close #25 2015-02-15 18:29:33 -05:00
josh 7698fbf618 add "rscons" binary - close #24 2015-02-08 18:04:37 -05:00
josh 4eedea2563 add Copy builder as a copy of Install 2015-02-07 09:57:44 -05:00
josh f678803a5d add Install builder - close #6 2015-02-07 09:49:29 -05:00
josh 9c49a09f69 update :spec rake task to allow example pattern as an argument 2015-01-29 09:58:09 -05:00
josh 859f87ddee add a Directory builder - close #27 2015-01-29 09:31:00 -05:00
josh 73bc71a656 test expanding paths after a build target is registered from within a build hook 2015-01-28 17:15:55 -05:00
josh 29a8684f90 support registering multiple build targets with the same path - close #26 2015-01-28 17:10:36 -05:00
josh 02aff35222 allow overriding Command builder short description with CMD_DESC variable -- close #22 2015-01-24 09:40:07 -05:00
josh 897d31ebe0 fix Command builder example invocation 2015-01-21 14:07:28 -05:00
josh 76610a07a9 fix variable references that expand to arrays in build target sources - fix #20 2015-01-20 21:26:45 -05:00
josh cb3cc9a0de update 1.9.0 release notes 2015-01-20 21:18:19 -05:00
josh 0ea842fffe rework Preprocess builder to consider deep dependencies - fix #21 2015-01-20 21:16:21 -05:00
josh d28722a4bb fix Rscons.set_suffix to append the given suffix if the filename has none 2015-01-20 21:13:27 -05:00
josh 8142d0bbc8 add v1.8.1 release notes 2015-01-20 21:12:57 -05:00
josh a8023ae03c v1.8.1 2014-10-22 14:30:32 -04:00
josh 99ba015630 fix Environment#dump when construction variables are Symbols 2014-10-22 14:30:14 -04:00
josh dcf90cc12b v1.8.0 2014-10-22 10:36:28 -04:00
josh f93ca62c07 add v1.8.0 release notes 2014-10-22 10:31:52 -04:00
josh d9e3129ad5 add Environment#dump 2014-10-22 10:30:57 -04:00
josh d5e0475e6c minor documentation improvements 2014-10-21 17:00:38 -04:00
josh b05eed36eb add VarSet#to_h 2014-10-21 16:06:15 -04:00
josh 7ea0721cc2 add a Builder#run method which raises an error unless overridden 2014-10-16 16:52:26 -04:00
josh e654df008d add rdoc to bundle 2014-10-16 16:42:03 -04:00
Michael D. Lowis 92d4dd8396 Implemented SimpleBuilder and updated Environment#add_builder method to support it 2014-10-16 16:37:37 -04:00
Michael D. Lowis e279959d79 Added a command builder to the list of default builders 2014-10-13 12:27:05 -04:00
131 changed files with 4122 additions and 1348 deletions

No files matched your search

+2 -1
View File
@@ -1,6 +1,7 @@
/.bundle/
/.yardoc/
/_yardoc/
/build_test_run/
/coverage/
/doc/
/pkg/
/build_test_run/
+27 -21
View File
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
rscons (1.7.0)
rscons (1.10.0)
json (~> 1.0)
GEM
@@ -9,28 +9,30 @@ GEM
specs:
diff-lcs (1.2.5)
docile (1.1.5)
json (1.8.1)
multi_json (1.10.1)
rake (10.3.2)
redcarpet (3.1.2)
rspec (3.0.0)
rspec-core (~> 3.0.0)
rspec-expectations (~> 3.0.0)
rspec-mocks (~> 3.0.0)
rspec-core (3.0.1)
rspec-support (~> 3.0.0)
rspec-expectations (3.0.1)
json (1.8.3)
rake (10.4.2)
rdoc (4.2.0)
json (~> 1.4)
redcarpet (3.3.3)
rspec (3.4.0)
rspec-core (~> 3.4.0)
rspec-expectations (~> 3.4.0)
rspec-mocks (~> 3.4.0)
rspec-core (3.4.1)
rspec-support (~> 3.4.0)
rspec-expectations (3.4.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.0.0)
rspec-mocks (3.0.1)
rspec-support (~> 3.0.0)
rspec-support (3.0.0)
simplecov (0.8.2)
rspec-support (~> 3.4.0)
rspec-mocks (3.4.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.4.0)
rspec-support (3.4.1)
simplecov (0.11.1)
docile (~> 1.1.0)
multi_json
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
yard (0.8.7.4)
json (~> 1.8)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
yard (0.8.7.6)
PLATFORMS
ruby
@@ -38,8 +40,12 @@ PLATFORMS
DEPENDENCIES
rake
rdoc
redcarpet
rscons!
rspec
simplecov
yard
BUNDLED WITH
1.10.6
+402 -121
View File
@@ -1,35 +1,36 @@
# Rscons
Software construction library inspired by SCons and implemented in Ruby
Rscons is a software construction framework inspired by SCons and implemented
in Ruby.
[![Gem Version](https://badge.fury.io/rb/rscons.png)](http://badge.fury.io/rb/rscons)
## Installation
Add this line to your application's Gemfile:
gem "rscons"
And then execute:
$ bundle install
Or install it yourself as:
$ gem install rscons
## Usage
Rscons is a Ruby library.
It can be called from a standalone Ruby script or it can be used with rake and
called from your Rakefile.
### 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", Dir["**/*.c"])
env.Program("program", Dir["src/**/*.c"])
end
```
@@ -38,7 +39,7 @@ end
```ruby
Rscons::Environment.new do |env|
env["DFLAGS"] << "-Wall"
env.Program("program", Dir["**/*.d"])
env.Program("program", Dir["src/**/*.d"])
end
```
@@ -154,6 +155,31 @@ Rscons::Environment.new do |env|
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
@@ -169,25 +195,6 @@ Rscons::Environment.new do |env|
end
```
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.
Build hooks can alter construction variable values for a particular build
operation. Build hooks can also register new build targets.
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.
### Example: Creating a static library
```ruby
@@ -206,96 +213,22 @@ end
## Details
### Builders
### Environments
Rscons ships with a number of builders:
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.
* 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
* 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
An Environment consists of:
If you want to create an Environment that does not contain any builders,
you can use the `exclude_builders` key to the Environment constructor.
#### 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.
#### Library
```ruby
env.Library(target, sources)
# Example
env.Library("lib.a", Dir["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.
#### 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", Dir["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`.
### Managing Environments
An Rscons::Environment consists of:
* a collection of construction variables
* 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 build directories are matched
* a collection of targets to build
* a collection of build hooks
* 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 and builders
are cloned, but the new environment does not inherit any of the targets, build
@@ -320,7 +253,235 @@ cloned_env["CPPPATH"] << "three"
`base_env["CPPPATH"]` will not include "three".
#### Build Hooks
### 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", Dir["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", Dir["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", Dir["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}"] |
| 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}"] |
| 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}"] |
| 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}", "${INCPREFIX}${D_IMPORT_PATH}", "${DFLAGS}", "${_SOURCES}"] |
| 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" |
| This name will include variant components. |
| The user should not change this construction variable. | Determined at runtime. |
| 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 | [] |
| 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 | [] |
| 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.
@@ -333,9 +494,68 @@ 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", *Dir.glob("assets/**/*"))
```
### 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
@@ -345,6 +565,67 @@ http://rubydoc.info/github/holtrop/rscons/frames.
## Release Notes
### v1.10.0
#### New Features
- #23 - add parallelization - builds are now parallelized by default
- #31 - add LEXSUFFIX, YACCSUFFIX construction variables
- #30 - place object files for absolute source paths under build_root
- #28 - support redirecting standard output using the Command builder
- Always use a build root and default it to "build"
- Add builder features
- #8 - add SharedObject and SharedLibrary builders
#### Fixes
- expand target and source paths before calling Builder#create_build_target
- #29 - fix PROGSUFFIX handling
### v1.9.3
- Environment#parse_flags should put -std=XXX flags in CCFLAGS, not CFLAGS
### v1.9.2
- allow phony targets in conjunction with build roots
### v1.9.1
- change *SUFFIX defaults to arrays
- add various C++ file suffixes
- use ${INCPREFIX} instead of hard-coded "-I" in Preprocess builder
### v1.9.0
#### New Features
- #6 - add Install and Copy builders
- #22 - allow overriding Command builder short description with CMD_DESC variable
- #24 - add "rscons" executable
- #25 - add support for phony targets given as Symbols instead of Strings
- #26 - support registering multiple build targets with the same target name
- #27 - add Directory builder
#### Fixes
- #20 - fix variable references that expand to arrays in build target sources
- #21 - rework Preprocess builder to consider deep dependencies
- fix Rscons.set_suffix to append the given suffix if the filename has none
- remove ${CFLAGS} from default CPP_CMD
### v1.8.1
- fix Environment#dump when construction variables are symbols
### v1.8.0
- new Command builder to execute arbitrary user commands
- new SimpleBuilder class
- create new builders quickly by passing a block to Environment#add_builder
- improved YARD documentation
- add Environment#dump to debug Environment construction variables
### v1.7.0
- allow build hooks to register new build targets
+6 -1
View File
@@ -13,7 +13,12 @@ require "rake/clean"
CLEAN.include %w[build_test_run .yardoc doc coverage]
CLOBBER.include %w[pkg]
RSpec::Core::RakeTask.new(:spec)
RSpec::Core::RakeTask.new(:spec, :example_string) do |task, args|
if args.example_string
ENV["partial_specs"] = "1"
task.rspec_opts = %W[-e "#{args.example_string}" -f documentation]
end
end
YARD::Rake::YardocTask.new do |yard|
yard.files = ['lib/**/*.rb']
Executable
+3
View File
@@ -0,0 +1,3 @@
require "rscons/cli"
Rscons::Cli.run(ARGV)
+5
View File
@@ -0,0 +1,5 @@
Rscons::Environment.new do |env|
env.append('CPPPATH' => Dir['src/**/*/'].sort)
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
env.Program('build_dir.exe', Dir['src/**/*.c'])
end
@@ -0,0 +1,22 @@
class MyObject < Rscons::Builder
def run(target, sources, cache, env, vars)
env.run_builder(env.builders["Object"], target, sources, cache, vars)
end
end
Rscons::Environment.new(echo: :command) do |env|
env.add_builder(MyObject.new)
env.append('CPPPATH' => Dir['src/**/*/'].sort)
env.add_build_hook do |build_op|
if build_op[:builder].name == "MyObject" && build_op[:sources].first =~ %r{one\.c}
build_op[:vars]["CFLAGS"] << "-O1"
build_op[:sources] = ['src/two/two.c']
elsif build_op[:builder].name == "MyObject" && build_op[:target] =~ %r{two\.o}
new_vars = build_op[:vars].clone
new_vars["CFLAGS"] << "-O2"
build_op[:vars] = new_vars
end
end
env.MyObject('one.o', 'src/one/one.c')
env.MyObject('two.o', 'src/two/two.c')
end
@@ -0,0 +1,6 @@
env = Rscons::Environment.new do |env|
env.append('CPPPATH' => Dir['src/**/*/'].sort)
env.build_dir("src", "build")
env.build_root = "build_root"
env.Program('build_dir.exe', Dir['src/**/*.c'])
end
+12
View File
@@ -0,0 +1,12 @@
Rscons::Environment.new(echo: :command) do |env|
env.append('CPPPATH' => Dir['src/**/*/'].sort)
env.build_dir(%r{^src/([^/]+)/}, 'build_\\1/')
env.add_build_hook do |build_op|
if build_op[:target] =~ %r{build_one/.*\.o}
build_op[:vars]["CFLAGS"] << "-O1"
elsif build_op[:target] =~ %r{build_two/.*\.o}
build_op[:vars]["CFLAGS"] << "-O2"
end
end
env.Program('build_hook.exe', Dir['src/**/*.c'].sort)
end
+8
View File
@@ -0,0 +1,8 @@
Rscons::Environment.new(echo: :command) do |env|
env.append('CPPPATH' => Dir['src/**/*/'].sort)
env.build_root = "build_root"
FileUtils.mkdir_p(env.build_root)
FileUtils.mv("src/one/one.c", "build_root")
env.Object("^/one.o", "^/one.c")
env.Program("build_dir.exe", Dir['src/**/*.c'] + ["^/one.o"])
end
+3
View File
@@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.Copy("inst.exe", "copy.rb")
end
+6
View File
@@ -0,0 +1,6 @@
Rscons::Environment.new do |env|
env["CSUFFIX"] = %w[.yargh .c]
env["CFLAGS"] += %w[-x c]
env["CPPPATH"] += Dir["src/**/"]
env.Program("build_dir.exe", Dir["src/**/*.{c,yargh}"])
end
+3
View File
@@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.Install("inst.exe", "install.rb")
end
@@ -0,0 +1,9 @@
Rscons::Environment.new do |env|
env.Directory("inst")
env.Install("inst", "install_directory.rb")
env.Install("noexist/src", "src")
env.Directory("exist/src")
env.Install("exist/src", "src")
end
@@ -0,0 +1,5 @@
Rscons::Environment.new do |env|
env["CPPPATH"] << "src/two"
env.Object("one.o", "src/one/one.c")
env.Object("one.o", "src/two/two.c")
end
@@ -0,0 +1,6 @@
Rscons::Environment.new do |env|
env.append('CPPPATH' => Dir['src/**/*/'].sort)
env.build_dir("src2", "build")
env.build_root = "build_root"
env.Program('build_dir.exe', Dir['src/**/*.c'])
end
@@ -0,0 +1,10 @@
Rscons::Environment.new do |env|
env["CPPPATH"] << "src/two"
env.Object("one.o", "src/one/one.c")
env.add_post_build_hook do |build_op|
if build_op[:target] == "one.o"
env["MODULE"] = "two"
env.Object("${MODULE}.o", "src/${MODULE}/${MODULE}.c")
end
end
end
+6
View File
@@ -0,0 +1,6 @@
Rscons::Environment.new do |env|
env.append("CPPPATH" => Dir["src/**/*/"].sort)
env.build_dir("src/one/", "build_one/")
env.build_dir("src/two", "build_two")
env.Program("build_dir.exe", Dir["src/**/*.c"])
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env.CFile("lexer.c", "lexer.l")
env.CFile("parser.c", "parser.y")
end
@@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.CFile("file.c", "foo.bar")
end
+4
View File
@@ -0,0 +1,4 @@
%{
%}
%%
+9
View File
@@ -0,0 +1,9 @@
%{
%}
%token ONE
%%
one: ONE
;
+12
View File
@@ -0,0 +1,12 @@
debug = Rscons::Environment.new(echo: :command) do |env|
env.build_dir('src', 'debug')
env['CFLAGS'] = '-O2'
env['CPPFLAGS'] = '-DSTRING="Debug Version"'
env.Program('program-debug.exe', Dir['src/*.c'])
end
release = debug.clone do |env|
env["CPPFLAGS"] = '-DSTRING="Release Version"'
env.build_dir('src', 'release')
env.Program('program-release.exe', Dir['src/*.c'])
end
+15
View File
@@ -0,0 +1,15 @@
env1 = Rscons::Environment.new(echo: :command) do |env|
env.build_dir('src', 'build')
env['CFLAGS'] = '-O2'
env.add_build_hook do |build_op|
build_op[:vars]['CPPFLAGS'] = '-DSTRING="Hello"'
end
env.add_post_build_hook do |build_op|
$stdout.puts "post #{build_op[:target]}"
end
env.Program('program.exe', Dir['src/*.c'])
end
env2 = env1.clone(clone: :all) do |env|
env.Program('program2.exe', Dir['src/*.c'])
end
+16
View File
@@ -0,0 +1,16 @@
class MySource < Rscons::Builder
def run(target, sources, cache, env, vars)
File.open(target, 'w') do |fh|
fh.puts <<EOF
#define THE_VALUE 5678
EOF
end
target
end
end
Rscons::Environment.new do |env|
env.add_builder(MySource.new)
env.MySource('inc.h', [])
env.Program('program.exe', Dir['*.c'])
end
@@ -0,0 +1,8 @@
Rscons::Environment.new do |env|
env.Command("inc.c",
[],
"CMD" => %w[ruby gen.rb ${_TARGET}],
"CMD_DESC" => "Generating")
env.build_after("#{env.build_root}/program.o", "inc.c")
env.Program("program.exe", ["program.c", "inc.c"])
end
@@ -0,0 +1,18 @@
class MySource < Rscons::Builder
def run(target, sources, cache, env, vars)
File.open(target, 'w') do |fh|
fh.puts <<EOF
#define THE_VALUE 678
EOF
end
target
end
end
env = Rscons::Environment.new do |env|
env["hdr"] = "inc.h"
env["src"] = "program.c"
env.add_builder(MySource.new)
env.MySource('${hdr}')
env.Program('program.exe', "${src}")
end
+28
View File
@@ -0,0 +1,28 @@
class MySource < Rscons::Builder
def run(target, sources, cache, env, vars)
File.open(target, 'w') do |fh|
fh.puts <<EOF
#define THE_VALUE #{env.expand_varref("${the_value}")}
EOF
end
target
end
end
e1 = Rscons::Environment.new do |env|
env.add_builder(MySource.new)
env["one"] = "5"
env[:cfg] = {val: "9"}
env["two"] = lambda do |args|
args[:env][:cfg][:val]
end
env["the_value"] = lambda do |args|
"${one}${two}78"
end
end
e1.clone do |env|
env[:cfg][:val] = "6"
env.MySource('inc.h', [])
env.Program('program.exe', Dir['*.c'])
end
+9
View File
@@ -0,0 +1,9 @@
sleep 1.0
c_file = ARGV.first
h_file = File.basename(c_file, ".c") + ".h"
File.open(c_file, "w") do |fh|
fh.puts
end
File.open(h_file, "w") do |fh|
fh.puts("#define THE_VALUE 191")
end
@@ -0,0 +1,19 @@
class CHGen < Rscons::Builder
def run(target, sources, cache, env, vars)
c_fname = target
h_fname = target.sub(/\.c$/, ".h")
unless cache.up_to_date?([c_fname, h_fname], "", sources, env)
puts "CHGen #{c_fname}"
File.open(c_fname, "w") {|fh| fh.puts "int THE_VALUE = 42;"}
File.open(h_fname, "w") {|fh| fh.puts "extern int THE_VALUE;"}
cache.register_build([c_fname, h_fname], "", sources, env)
end
target
end
end
Rscons::Environment.new do |env|
env.add_builder(CHGen.new)
env.CHGen("inc.c", ["program.c"])
env.Program("program.exe", %w[program.c inc.c])
end
+3
View File
@@ -0,0 +1,3 @@
Rscons::Environment.new(echo: :command) do |env|
env.Program("hello-d.exe", Dir["*.d"])
end
+3
View File
@@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.Program('header.exe', Dir['*.c'])
end
+15
View File
@@ -0,0 +1,15 @@
Rscons::Environment.new do |env|
require 'json'
require 'yaml'
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
+1
View File
@@ -0,0 +1 @@
{ "key": "value" }
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new(echo: :command) do |env|
env.Program('library.exe', ['lib.a', 'three.c'])
env.Library("lib.a", ['one.c', 'two.c'], 'CPPFLAGS' => ['-Dmake_lib'])
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new(echo: :command) do |env|
env["ARCMD"] = %w[ar rcf ${_TARGET} ${_SOURCES}]
env.Library("lib.a", Dir["*.c"].sort)
end
+3
View File
@@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.Preprocess("pp", "foo.h")
end
+1
View File
@@ -0,0 +1 @@
#define BAR xyz42abc
+2
View File
@@ -0,0 +1,2 @@
#include "bar.h"
BAR
+11
View File
@@ -0,0 +1,11 @@
Rscons::Environment.new do |env|
env["CPPPATH"] << "src/lib"
libmine = env.SharedLibrary("mine", Dir["src/lib/*.c"])
env.Program("test-shared.exe",
Dir["src/*.c"],
"LIBPATH" => %w[.],
"LIBS" => %w[mine])
env.build_after("test-shared.exe", libmine.to_s)
env.Program("test-static.exe",
Dir["src/**/*.c"])
end
@@ -0,0 +1,6 @@
Rscons::Environment.new do |env|
File.open("foo.xyz", "wb") do |fh|
fh.puts("hi")
end
env.SharedObject("foo.o", "foo.xyz")
end
@@ -0,0 +1,11 @@
Rscons::Environment.new do |env|
env["CPPPATH"] << "src/lib"
libmine = env.SharedLibrary("mine", Dir["src/lib/*.cc"])
env.Program("test-shared.exe",
Dir["src/*.cc"],
"LIBPATH" => %w[.],
"LIBS" => %w[mine])
env.build_after("test-shared.exe", libmine.to_s)
env.Program("test-static.exe",
Dir["src/**/*.cc"])
end
@@ -0,0 +1,9 @@
Rscons::Environment.new do |env|
env["CPPPATH"] << "src/lib"
libmine = env.SharedLibrary("mine", Dir["src/lib/*.d"])
env.Program("test-shared.exe",
Dir["src/*.c"],
"LIBPATH" => %w[.],
"LIBS" => %w[mine])
env.build_after("test-shared.exe", libmine.to_s)
end
@@ -0,0 +1,12 @@
Rscons::Environment.new do |env|
env["CPPPATH"] << "src/lib"
env["SHLD"] = "gcc"
libmine = env.SharedLibrary("mine", Dir["src/lib/*.c"])
env.Program("test-shared.exe",
Dir["src/*.c"],
"LIBPATH" => %w[.],
"LIBS" => %w[mine])
env.build_after("test-shared.exe", libmine.to_s)
env.Program("test-static.exe",
Dir["src/**/*.c"])
end
+6
View File
@@ -0,0 +1,6 @@
#include <stdio.h>
void one(void)
{
printf("Hi from one()\n");
}
@@ -0,0 +1,6 @@
#include <stdio.h>
void one(void)
{
printf("Hi from one()\n");
}
+6
View File
@@ -0,0 +1,6 @@
import core.stdc.stdio;
extern (C) void one()
{
printf("Hi from one()\n");
}
+5
View File
@@ -0,0 +1,5 @@
#ifndef ONE_H
void one(void);
#endif
+6
View File
@@ -0,0 +1,6 @@
#include <stdio.h>
void two(void)
{
printf("Hi from two()\n");
}
@@ -0,0 +1,6 @@
#include <stdio.h>
void two(void)
{
printf("Hi from two()\n");
}
+6
View File
@@ -0,0 +1,6 @@
import core.stdc.stdio;
extern (C) void two()
{
printf("Hi from two()\n");
}
+5
View File
@@ -0,0 +1,5 @@
#ifndef TWO_H
void two(void);
#endif
+8
View File
@@ -0,0 +1,8 @@
#include "one.h"
#include "two.h"
int main(int argc, char * argv[])
{
one();
two();
}
+8
View File
@@ -0,0 +1,8 @@
#include "one.h"
#include "two.h"
int main(int argc, char * argv[])
{
one();
two();
}
+3
View File
@@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.Program('simple.exe', Dir['*.c'])
end
@@ -0,0 +1,14 @@
Rscons::Environment.new do |env|
env.build_root = "build"
tempdir = ENV["TEMP"] || ENV["TMP"] || "/tmp"
source_file = File.join(tempdir, "abs.c")
File.open(source_file, "w") do |fh|
fh.puts(<<-EOF)
int main()
{
return 29;
}
EOF
end
env.Program("abs.exe", source_file)
end
+28
View File
@@ -0,0 +1,28 @@
class MyObject < Rscons::Builder
def produces?(target, source, env)
target.end_with?(".o") and source.end_with?(".xyz")
end
def run(target, sources, cache, env, vars)
cflags = env.expand_varref("${CFLAGS}", vars)
vars = vars.merge(
"CFLAGS" => cflags + %w[-x c],
"CSUFFIX" => ".xyz")
env.run_builder(env.builders["Object"], target, sources, cache, vars)
end
end
Rscons::Environment.new do |env|
env.add_builder(MyObject.new)
File.open("test.xyz", "w") do |fh|
fh.puts <<EOF
#include <stdio.h>
int main(int argc, char * argv[])
{
printf("XYZ!\\n");
return 0;
}
EOF
env.Program("test", "test.xyz")
end
end
@@ -0,0 +1,10 @@
class TestBuilder < Rscons::Builder
def run(target, sources, cache, env, vars)
target
end
end
Rscons::Environment.new do |env|
env.build_root = "build"
env.add_builder(TestBuilder.new)
env.TestBuilder("file")
end
+22
View File
@@ -0,0 +1,22 @@
class MyProgram < Rscons::Builder
def run(options)
target, sources, cache, env, vars = options.values_at(:target, :sources, :cache, :env, :vars)
objects = env.build_sources(sources, [".o"], cache, vars)
command = %W[gcc -o #{target}] + objects
return false unless env.execute("#{name} #{target}", command)
target
end
end
Rscons::Environment.new do |env|
env.add_builder(MyProgram.new)
env.Object("simple.o", "simple.c")
File.open("two.c", "wb") do |fh|
fh.puts <<-EOF
void two(void)
{
}
EOF
end
env.MyProgram("simple.exe", ["simple.o", "two.c"])
end
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env["LIBS"] += ["c"]
env.Program('simple.exe', Dir['*.c'])
end
@@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.Copy("simple.copy", "simple.c")
end
+6
View File
@@ -0,0 +1,6 @@
Rscons::Environment.new do |env|
env.Object("simple.o", "simple.c")
env.process
env["LDCMD"] = %w[gcc -o ${_TARGET} simple.o]
env.Program('simple.exe', [])
end
+5
View File
@@ -0,0 +1,5 @@
Rscons::Environment.new do |env|
env.Object("simple.o", "simple.c")
env["LDCMD"] = %w[gcc -o ${_TARGET} simple.o]
env.Program('simple.exe', ["simple.o"])
end
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env.Object("simple.o", "simple.c")
env.Object("two.o", "two.c")
end
+5
View File
@@ -0,0 +1,5 @@
Rscons::Environment.new do |env|
target = env.Program("simple.exe", "simple.c")
user_deps = File.read("user_deps", mode: "rb").split(" ")
target.depends(*user_deps)
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env.Program("simple.exe", "simple.c")
env.clear_targets
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new(echo: :command) do |env|
env["LD"] = "gcc"
env.Program('simple.exe', Dir['*.c'])
end
+7
View File
@@ -0,0 +1,7 @@
Rscons::Environment.new do |env|
command = %W[gcc -o ${_TARGET} ${_SOURCES}]
env.Command("simple.exe",
"simple.c",
"CMD" => command,
"CMD_DESC" => "BuildIt")
end
+8
View File
@@ -0,0 +1,8 @@
Rscons::Environment.new do |env|
env.Object("simple.o", "simple.c")
env.Command("simple.txt",
"simple.o",
"CMD" => %w[objdump --disassemble --source ${_SOURCES}],
"CMD_STDOUT" => "${_TARGET}",
"CMD_DESC" => "My Disassemble")
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env["sources"] = Dir["*.c"].sort
env.Program("simple.exe", "${sources}")
end
+3
View File
@@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.Directory("teh_dir")
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env.Object("simple.o", "simple.c")
env.Disassemble("simple.txt", "simple.o")
end
+5
View File
@@ -0,0 +1,5 @@
env = Rscons::Environment.new do |env|
env["CFLAGS"] += %w[-O2 -fomit-frame-pointer]
env[:foo] = :bar
end
env.dump
@@ -0,0 +1,6 @@
Rscons::Environment.new do |env|
File.open("foo.xyz", "wb") do |fh|
fh.puts("hi")
end
env.Object("foo.o", "foo.xyz")
end
+5
View File
@@ -0,0 +1,5 @@
Rscons::Environment.new(echo: :command) do |env|
env["LD"] = "gcc"
env["LIBPATH"] += ["libdir"]
env.Program('simple.exe', Dir['*.c'])
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new(echo: :command) do |env|
env.Object("simple.o", "simple.c",
"CCCMD" => %w[${CC} -c -o ${_TARGET} -Dfoobar ${_SOURCES}])
end
@@ -0,0 +1,4 @@
Rscons::Environment.new(echo: :command) do |env|
env["DEPFILESUFFIX"] = ".deppy"
env.Object("simple.o", "simple.c")
end
+11
View File
@@ -0,0 +1,11 @@
Rscons::Environment.new do |env|
env.add_builder(:Checker) do |target, sources, cache, env, vars|
unless cache.up_to_date?(target, :Checker, sources, env)
puts "Checker #{sources.first}" if env.echo != :off
cache.register_build(target, :Checker, sources, env)
end
target
end
env.Program("simple.exe", "simple.c")
env.Checker(:checker, "simple.exe")
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env.Preprocess("simplepp.c", "simple.c")
env.Program("simple.exe", "simplepp.c")
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env["PROGSUFFIX"] = ".out"
env.Program("simple", Dir["*.c"])
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env["MYSUFFIX"] = ".out"
env.Program("simple${MYSUFFIX}", Dir["*.c"])
end
+3
View File
@@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.Program("simple", Dir["*.c"], "PROGSUFFIX" => ".xyz")
end
@@ -0,0 +1,8 @@
Rscons::Environment.new do |env|
env.Program("simple.exe", Dir["*.c"])
env.add_build_hook do |build_op|
if build_op[:target].end_with?(".o")
env.Disassemble("#{build_op[:target]}.txt", build_op[:target])
end
end
end
+12
View File
@@ -0,0 +1,12 @@
class MyObject < Rscons::Builder
def run(options)
target, sources, cache, env, vars = options.values_at(:target, :sources, :cache, :env, :vars)
env.run_builder(env.builders["Object"], target, sources, cache, vars)
end
end
Rscons::Environment.new do |env|
env.add_builder(MyObject.new)
env.MyObject("simple.o", "simple.c")
env.Program("simple.exe", "simple.o")
end
+17
View File
@@ -0,0 +1,17 @@
class MyCommand < Rscons::Builder
def run(target, sources, cache, env, vars)
vars = vars.merge({
"_TARGET" => target,
"_SOURCES" => sources,
})
command = env.build_command("${CMD}", vars)
cmd_desc = vars["CMD_DESC"] || "MyCommand"
standard_build("#{cmd_desc} #{target}", target, command, sources, env, cache)
end
end
Rscons::Environment.new do |env|
env.add_builder(MyCommand.new)
command = %w[gcc -c -o ${_TARGET} ${_SOURCES}]
env.MyCommand("simple.o", "simple.c", "CMD" => command)
end
+28
View File
@@ -0,0 +1,28 @@
class ThreadedTestBuilder < Rscons::Builder
def run(options)
command = ["ruby", "-e", %[sleep 1]]
Rscons::ThreadedCommand.new(
command,
short_description: "ThreadedTestBuilder #{options[:target]}")
end
def finalize(options)
true
end
end
class NonThreadedTestBuilder < Rscons::Builder
def run(options)
puts "NonThreadedTestBuilder #{options[:target]}"
sleep 1
options[:target]
end
end
Rscons::Environment.new do |env|
env.add_builder(ThreadedTestBuilder.new)
env.add_builder(NonThreadedTestBuilder.new)
env.ThreadedTestBuilder("a")
env.ThreadedTestBuilder("b")
env.ThreadedTestBuilder("c")
env.NonThreadedTestBuilder("d")
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
program = env.Program("simple.exe", Dir["*.c"])
env.depends(program, "program.ld")
end
+3
View File
@@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.Program('simple.exe', Dir['*.cc'])
end
+5
View File
@@ -0,0 +1,5 @@
Rscons::Environment.new do |env|
env["CXXSUFFIX"] = %w[.cccc .cc]
env["CXXFLAGS"] += %w[-x c++]
env.Program("simple.exe", Dir["*.cc"] + Dir["*.cccc"])
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env.Preprocess("simplepp.cc", "simple.cc")
env.Program("simple.exe", "simplepp.cc")
end
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new(echo: :command) do |env|
env.Object("one.o", "one.c", 'CPPFLAGS' => ['-DONE'])
env.Program('two_sources.exe', ['one.o', 'two.c'])
end
+7
View File
@@ -0,0 +1,7 @@
Rscons::Environment.new do |env|
env["ASSUFFIX"] = %w[.ssss .sss]
env["CFLAGS"] += %w[-S]
env.Object("one.ssss", "one.c", "CPPFLAGS" => ["-DONE"])
env.Object("two.sss", "two.c")
env.Program("two_sources.exe", %w[one.ssss two.sss], "ASFLAGS" => env["ASFLAGS"] + %w[-x assembler])
end
@@ -0,0 +1,19 @@
class StrictBuilder < Rscons::Builder
def run(options)
target, sources, cache, env = options.values_at(:target, :sources, :cache, :env)
command = %W[gcc -o #{target}] + sources.sort
unless cache.up_to_date?(target, command, sources, env, strict_deps: true)
return false unless env.execute("StrictBuilder #{target}", command)
cache.register_build(target, command, sources, env)
end
target
end
end
Rscons::Environment.new(echo: :command) do |env|
env.add_builder(StrictBuilder.new)
env.Object("one.o", "one.c", "CCFLAGS" => %w[-DONE])
env.Object("two.o", "two.c")
sources = File.read("sources", mode: "rb").split(" ")
env.StrictBuilder("program.exe", sources)
end
+6
View File
@@ -0,0 +1,6 @@
Rscons::Environment.new() do |env|
env["LIBSUFFIX"] = %w[.aaaa .aaa]
env.Library("one.aaaa", "one.c", "CPPFLAGS" => ["-DONE"])
env.Library("two.aaa", "two.c")
env.Program("two_sources.exe", %w[one.aaaa two.aaa])
end
+6
View File
@@ -0,0 +1,6 @@
Rscons::Environment.new do |env|
env["OBJSUFFIX"] = %w[.oooo .ooo]
env.Object("one.oooo", "one.c", "CPPFLAGS" => ["-DONE"])
env.Object("two.ooo", "two.c")
env.Program("two_sources.exe", %w[one.oooo two.ooo])
end
+153 -75
View File
@@ -2,125 +2,203 @@ require_relative "rscons/build_target"
require_relative "rscons/builder"
require_relative "rscons/cache"
require_relative "rscons/environment"
require_relative "rscons/job_set"
require_relative "rscons/threaded_command"
require_relative "rscons/varset"
require_relative "rscons/version"
# default builders
require_relative "rscons/builders/cfile"
require_relative "rscons/builders/command"
require_relative "rscons/builders/directory"
require_relative "rscons/builders/disassemble"
require_relative "rscons/builders/install"
require_relative "rscons/builders/library"
require_relative "rscons/builders/object"
require_relative "rscons/builders/preprocess"
require_relative "rscons/builders/program"
require_relative "rscons/builders/shared_library"
require_relative "rscons/builders/shared_object"
require_relative "rscons/builders/simple_builder"
# Namespace module for rscons classes
module Rscons
# Names of the default builders which will be added to all newly created
# {Environment} objects.
DEFAULT_BUILDERS = [
:CFile,
:Command,
:Copy,
:Directory,
:Disassemble,
:Install,
:Library,
:Object,
:Preprocess,
:Program,
:SharedLibrary,
:SharedObject,
]
# Class to represent a fatal error while building a target.
class BuildError < RuntimeError; end
# Remove all generated files.
def self.clean
cache = Cache.instance
# remove all built files
cache.targets.each do |target|
FileUtils.rm_f(target)
class << self
# @return [Integer]
# The number of threads to use when scheduling subprocesses.
attr_accessor :n_threads
# Remove all generated files.
#
# @return [void]
def clean
cache = Cache.instance
# remove all built files
cache.targets.each do |target|
FileUtils.rm_f(target)
end
# remove all created directories if they are empty
cache.directories.sort {|a, b| b.size <=> a.size}.each do |directory|
next unless File.directory?(directory)
if (Dir.entries(directory) - ['.', '..']).empty?
Dir.rmdir(directory) rescue nil
end
end
cache.clear
end
# remove all created directories if they are empty
cache.directories.sort {|a, b| b.size <=> a.size}.each do |directory|
next unless File.directory?(directory)
if (Dir.entries(directory) - ['.', '..']).empty?
Dir.rmdir(directory) rescue nil
# Return whether the given path is an absolute filesystem path.
#
# @param path [String] the path to examine.
#
# @return [Boolean] Whether the given path is an absolute filesystem path.
def absolute_path?(path)
if RUBY_PLATFORM =~ /mingw/
path =~ %r{^(?:\w:)?[\\/]}
else
path.start_with?("/")
end
end
cache.clear
end
# Return whether the given path is an absolute filesystem path.
#
# @param path [String] the path to examine.
#
# @return [Boolean] Whether the given path is an absolute filesystem path.
def self.absolute_path?(path)
path =~ %r{^(/|\w:[\\/])}
end
# Return whether the given target is a phony target.
#
# @param target [Symbol, String] Target name.
#
# @return [Boolean] Whether the given target is a phony target.
def phony_target?(target)
target.is_a?(Symbol)
end
# Return a new path by changing the suffix in path to suffix.
#
# @param path [String] The path to alter.
# @param suffix [String] The new filename suffix, e.g. ".exe".
#
# @return [String] New path.
def self.set_suffix(path, suffix)
path.sub(/\.[^.]*$/, suffix)
end
# Return a new path by changing the suffix in path to suffix.
#
# @param path [String] The path to alter.
# @param suffix [String] The new filename suffix, e.g. ".exe".
#
# @return [String] New path.
def set_suffix(path, suffix)
path.sub(/\.[^.]*$/, "") + suffix
end
# Return the system shell and arguments for executing a shell command.
#
# @return [Array<String>] The shell and flag.
def self.get_system_shell
@@shell ||=
begin
test_shell = lambda do |*args|
begin
"success" == IO.popen([*args, "echo success"]) do |io|
io.read.strip
# Return the system shell and arguments for executing a shell command.
#
# @return [Array<String>] The shell and flag.
def get_system_shell
@shell ||=
begin
test_shell = lambda do |*args|
begin
"success" == IO.popen([*args, "echo success"]) do |io|
io.read.strip
end
rescue
false
end
rescue
false
end
end
if ENV["SHELL"] and ENV["SHELL"] != "" and test_shell[ENV["SHELL"], "-c"]
[ENV["SHELL"], "-c"]
elsif Object.const_get("RUBY_PLATFORM") =~ /mingw/
if test_shell["sh", "-c"]
# Using Rscons from MSYS should use MSYS's shell.
["sh", "-c"]
if ENV["SHELL"] and ENV["SHELL"] != "" and test_shell[ENV["SHELL"], "-c"]
[ENV["SHELL"], "-c"]
elsif Object.const_get("RUBY_PLATFORM") =~ /mingw/
if test_shell["sh", "-c"]
# Using Rscons from MSYS should use MSYS's shell.
["sh", "-c"]
else
["cmd", "/c"]
end
else
["cmd", "/c"]
["sh", "-c"]
end
else
["sh", "-c"]
end
end
end
end
# Return an Array containing a command used to execute commands.
#
# This will normally be an empty Array, but on Windows if Rscons detects
# that it is running in MSYS then ["env"] will be returned.
#
# @return [Array<String>] Command used to execute commands.
def self.command_executer
@@command_executer ||=
if Object.const_get("RUBY_PLATFORM") =~ /mingw/
if ENV.keys.find {|key| key =~ /MSYS/}
begin
if IO.popen(["env", "echo", "success"]) {|io| io.read.strip} == "success"
["env"]
# Return an Array containing a command used to execute commands.
#
# This will normally be an empty Array, but on Windows if Rscons detects
# that it is running in MSYS then ["env"] will be returned.
#
# @return [Array<String>] Command used to execute commands.
def command_executer
@command_executer ||=
if Object.const_get("RUBY_PLATFORM") =~ /mingw/
if ENV.keys.find {|key| key =~ /MSYS/}
begin
if IO.popen(["env", "echo", "success"]) {|io| io.read.strip} == "success"
["env"]
end
rescue
end
rescue
end
end || []
end
# Set the command executer array.
#
# @param val [Array<String>] Command used to execute commands.
#
# @return [Array<String>] Command used to execute commands.
def command_executer=(val)
@command_executer = val
end
private
# Determine the number of threads to use by default.
#
# @return [Integer]
# The number of threads to use by default.
def determine_n_threads
# If the user specifies the number of threads in the environment, then
# respect that.
if ENV["RSCONS_NTHREADS"] =~ /^(\d+)$/
return $1.to_i
end
# Otherwise try to figure out how many threads are available on the
# host hardware.
begin
case RbConfig::CONFIG["host_os"]
when /linux/
return File.read("/proc/cpuinfo").scan(/^processor\s*:/).size
when /mswin|mingw/
if `wmic cpu get NumberOfLogicalProcessors /value` =~ /NumberOfLogicalProcessors=(\d+)/
return $1.to_i
end
when /darwin/
if `sysctl -n hw.ncpu` =~ /(\d+)/
return $1.to_i
end
end
end || []
rescue
end
# If we can't figure it out, default to 1.
1
end
end
# Set the command executer array.
#
# @param val [Array<String>] Command used to execute commands.
def self.command_executer=(val)
@@command_executer = val
end
@n_threads = determine_n_threads
end
# Unbuffer $stdout
+197 -6
View File
@@ -9,6 +9,8 @@ module Rscons
# Return the name of the builder.
#
# If not overridden this defaults to the last component of the class name.
#
# @return [String] The name of the builder.
def name
self.class.name.split(":").last
end
@@ -22,6 +24,14 @@ module Rscons
{}
end
# Return a set of build features that this builder provides.
#
# @return [Array<String>]
# Set of build features that this builder provides.
def features
[]
end
# Create a BuildTarget object for this build target.
#
# Builder sub-classes can override this method to manipulate parameters
@@ -34,6 +44,8 @@ module Rscons
# The user-supplied target name.
# @option options [Array<String>] :sources
# The user-supplied source file name(s).
# @option options [Hash,VarSet] :vars
# Extra construction variables.
#
# @return [BuildTarget]
def create_build_target(options)
@@ -43,9 +55,12 @@ module Rscons
# Return whether this builder object is capable of producing a given target
# file name from a given source file name.
#
# @param target [String] The target file name.
# @param source [String, Array] The source file name(s).
# @param env [Environment] The Environment.
# @param target [String]
# The target file name.
# @param source [String]
# The source file name.
# @param env [Environment]
# The Environment.
#
# @return [Boolean]
# Whether this builder object is capable of producing a given target
@@ -54,8 +69,128 @@ module Rscons
false
end
# Set up a build operation using this builder.
#
# This method is called when a build target is registered using this
# builder. This method should not do any building, but should perform any
# setup needed and register any prerequisite build targets that need to be
# built before the target being requested here.
#
# If the builder needs no special setup, it does not need to override this
# method. If there is any information produced in this method that will be
# needed later in the build, it can be stored in the return value from this
# method, which will be passed to the {#run} method.
#
# @since 1.10.0
#
# @param options [Hash]
# Options.
# @option options [String] :target
# Target file name.
# @option options [Array<String>] :sources
# Source file name(s).
# @option options [Environment] :env
# The Environment executing the builder.
# @option options [Hash,VarSet] :vars
# Extra construction variables.
#
# @return [Object]
# Any object that the builder author wishes to be saved and passed back
# in to the {#run} method.
def setup(options)
end
# Run the builder to produce a build target.
#
# The run method supports two different signatures - an older signature
# with five separate arguments, and a newer one with one Hash argument. A
# builder author can use either signature, and Rscons will automatically
# determine which arguments to pass when invoking the run method based on
# the method's arity.
#
# @overload run(target, sources, cache, env, vars)
#
# @param target [String]
# Target file name.
# @param sources [Array<String>]
# Source file name(s).
# @param cache [Cache]
# The Cache object.
# @param env [Environment]
# The Environment executing the builder.
# @param vars [Hash,VarSet]
# Extra construction variables.
#
# @overload run(options)
#
# @since 1.10.0
#
# @param options [Hash]
# Run options.
# @option options [String] :target
# Target file name.
# @option options [Array<String>] :sources
# Source file name(s).
# @option options [Cache] :cache
# The Cache object.
# @option options [Environment] :env
# The Environment executing the builder.
# @option options [Hash,VarSet] :vars
# Extra construction variables.
# @option options [Object] :setup_info
# Whatever value was returned from this builder's {#setup} method call.
#
# @return [ThreadedCommand,String,false]
# Name of the target file on success or false on failure.
# Since 1.10.0, this method may return an instance of {ThreadedCommand}.
# In that case, the build operation has not actually been completed yet
# but the command to do so will be executed by Rscons in a separate
# thread. This allows for build parallelization. If a {ThreadedCommand}
# object is returned, the {#finalize} method will be called after the
# command has completed. The {#finalize} method should then be used to
# record cache info, if needed, and to return the true result of the
# build operation. The builder can store information to be passed in to
# the {#finalize} method by populating the :builder_info field of the
# {ThreadedCommand} object returned here.
def run(options)
raise "This method must be overridden in a subclass"
end
# Finalize a build operation.
#
# This method is called after the {#run} method if the {#run} method
# returns a {ThreadedCommand} object.
#
# @since 1.10.0
#
# @param options [Hash]
# Options.
# @option options [String] :target
# Target file name.
# @option options [Array<String>] :sources
# Source file name(s).
# @option options [Cache] :cache
# The Cache object.
# @option options [Environment] :env
# The Environment executing the builder.
# @option options [Hash,VarSet] :vars
# Extra construction variables.
# @option options [Object] :setup_info
# Whatever value was returned from this builder's {#setup} method call.
# @option options [true,false,nil] :command_status
# If the {#run} method returns a {ThreadedCommand}, this field will
# contain the return value from executing the command with
# Kernel.system().
# @option options [ThreadedCommand] :tc
# The {ThreadedCommand} object that was returned by the #run method.
#
# @return [String,false]
# Name of the target file on success or false on failure.
def finalize(options)
end
# Check if the cache is up to date for the target and if not execute the
# build command.
# build command. This method does not support parallelization.
#
# @param short_cmd_string [String]
# Short description of build action to be printed when env.echo ==
@@ -71,12 +206,68 @@ module Rscons
# The name of the target on success or false on failure.
def standard_build(short_cmd_string, target, command, sources, env, cache)
unless cache.up_to_date?(target, command, sources, env)
cache.mkdir_p(File.dirname(target))
FileUtils.rm_f(target)
unless Rscons.phony_target?(target)
cache.mkdir_p(File.dirname(target))
FileUtils.rm_f(target)
end
return false unless env.execute(short_cmd_string, command)
cache.register_build(target, command, sources, env)
end
target
end
# Check if the cache is up to date for the target and if not create a
# {ThreadedCommand} object to execute the build command in a thread.
#
# @since 1.10.0
#
# @param short_cmd_string [String]
# Short description of build action to be printed when env.echo ==
# :short.
# @param target [String] Name of the target file.
# @param command [Array<String>]
# The command to execute to build the target.
# @param sources [Array<String>] Source file name(s).
# @param env [Environment] The Environment executing the builder.
# @param cache [Cache] The Cache object.
# @param options [Hash] Options.
# @options options [String] :stdout
# File name to redirect standard output to.
#
# @return [String,ThreadedCommand]
# The name of the target if it is already up to date or the
# {ThreadedCommand} object created to update it.
def standard_threaded_build(short_cmd_string, target, command, sources, env, cache, options = {})
if cache.up_to_date?(target, command, sources, env)
target
else
unless Rscons.phony_target?(target)
cache.mkdir_p(File.dirname(target))
FileUtils.rm_f(target)
end
tc_options = {short_description: short_cmd_string}
if options[:stdout]
tc_options[:system_options] = {out: options[:stdout]}
end
ThreadedCommand.new(command, tc_options)
end
end
# Register build results from a {ThreadedCommand} with the cache.
#
# @since 1.10.0
#
# @param options [Hash]
# Builder finalize options.
#
# @return [String, nil]
# The target name on success or nil on failure.
def standard_finalize(options)
if options[:command_status]
target, sources, cache, env = options.values_at(:target, :sources, :cache, :env)
cache.register_build(target, options[:tc].command, sources, env)
target
end
end
end
end
+18 -3
View File
@@ -7,6 +7,7 @@ module Rscons
# env.CFile("parser.tab.cc", "parser.yy")
# env.CFile("lex.yy.cc", "parser.ll")
class CFile < Builder
# Return default construction variables for the builder.
#
# @param env [Environment] The Environment using the builder.
@@ -17,9 +18,11 @@ module Rscons
"YACC" => "bison",
"YACC_FLAGS" => ["-d"],
"YACC_CMD" => ["${YACC}", "${YACC_FLAGS}", "-o", "${_TARGET}", "${_SOURCES}"],
"YACCSUFFIX" => [".y", ".yy"],
"LEX" => "flex",
"LEX_FLAGS" => [],
"LEX_CMD" => ["${LEX}", "${LEX_FLAGS}", "-o", "${_TARGET}", "${_SOURCES}"],
"LEXSUFFIX" => [".l", ".ll"],
}
end
@@ -40,16 +43,28 @@ module Rscons
})
cmd =
case
when sources.first.end_with?(".l", ".ll")
when sources.first.end_with?(*env.expand_varref("${LEXSUFFIX}"))
"LEX"
when sources.first.end_with?(".y", ".yy")
when sources.first.end_with?(*env.expand_varref("${YACCSUFFIX}"))
"YACC"
else
raise "Unknown source file #{sources.first.inspect} for CFile builder"
end
command = env.build_command("${#{cmd}_CMD}", vars)
standard_build("#{cmd} #{target}", target, command, sources, env, cache)
standard_threaded_build("#{cmd} #{target}", target, command, sources, env, cache)
end
# Finalize a build.
#
# @param options [Hash]
# Finalize options.
#
# @return [String, nil]
# The target name on success or nil on failure.
def finalize(options)
standard_finalize(options)
end
end
end
end
+48
View File
@@ -0,0 +1,48 @@
module Rscons
module Builders
# Execute a command that will produce the given target based on the given
# sources.
#
# @since 1.8.0
#
# Example:
# env.Command("docs.html", "docs.md",
# CMD => %w[pandoc -fmarkdown -thtml -o${_TARGET} ${_SOURCES}])
class Command < Builder
# Run the builder to produce a build target.
#
# @param options [Hash] Builder run options.
#
# @return [String, ThreadedCommand]
# Target file name if target is up to date or a {ThreadedCommand}
# to execute to build the target.
def run(options)
target, sources, cache, env, vars = options.values_at(:target, :sources, :cache, :env, :vars)
vars = vars.merge({
"_TARGET" => target,
"_SOURCES" => sources,
})
command = env.build_command("${CMD}", vars)
cmd_desc = vars["CMD_DESC"] || "Command"
options = {}
if vars["CMD_STDOUT"]
options[:stdout] = env.expand_varref("${CMD_STDOUT}", vars)
end
standard_threaded_build("#{cmd_desc} #{target}", target, command, sources, env, cache, options)
end
# Finalize a build.
#
# @param options [Hash]
# Finalize options.
#
# @return [String, nil]
# The target name on success or nil on failure.
def finalize(options)
standard_finalize(options)
end
end
end
end
+31
View File
@@ -0,0 +1,31 @@
module Rscons
module Builders
# The Directory builder creates a directory.
class Directory < Builder
# Run the builder to produce a build target.
#
# @param target [String] Target file name.
# @param sources [Array<String>] Source file name(s).
# @param cache [Cache] The Cache object.
# @param env [Environment] The Environment executing the builder.
# @param vars [Hash,VarSet] Extra construction variables.
#
# @return [String,false]
# Name of the target file on success or false on failure.
def run(target, sources, cache, env, vars)
if File.directory?(target)
target
elsif File.exists?(target)
$stderr.puts "Error: `#{target}' already exists and is not a directory"
false
else
puts "Directory #{target}"
cache.mkdir_p(target)
target
end
end
end
end
end
Loaded 100 of 131 files, more files were not shown because too many files have changed in this diff. Show more