Compare commits
9 Commits
7055cad73c
...
f5ab51c477
Author | SHA1 | Date | |
---|---|---|---|
f5ab51c477 | |||
b0f2bbb7d5 | |||
c1dcfa297f | |||
034dbcd9a6 | |||
b5d5fe7a7b | |||
610b8f1266 | |||
a316c4f922 | |||
97dbaeb82d | |||
a2f72c6b87 |
4
build_tests/sh/sh.rb
Normal file
4
build_tests/sh/sh.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
build do
|
||||||
|
sh "echo", "hi there"
|
||||||
|
sh(["echo 1 2"])
|
||||||
|
end
|
4
build_tests/sh/sh_fail.rb
Normal file
4
build_tests/sh/sh_fail.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
build do
|
||||||
|
sh "foobar42"
|
||||||
|
sh "echo", "continued"
|
||||||
|
end
|
4
build_tests/sh/sh_fail_continue.rb
Normal file
4
build_tests/sh/sh_fail_continue.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
build do
|
||||||
|
sh "foobar42", continue: true
|
||||||
|
sh "echo", "continued"
|
||||||
|
end
|
6
build_tests/simple/size.rb
Normal file
6
build_tests/simple/size.rb
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.Program("simple.exe", glob("*.c"))
|
||||||
|
env.Size("simple.size", "simple.exe")
|
||||||
|
end
|
||||||
|
end
|
6
build_tests/typical/Rsconscript
Normal file
6
build_tests/typical/Rsconscript
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
build do
|
||||||
|
Environment.new(name: "typical") do |env|
|
||||||
|
env["CPPPATH"] += glob("src/**")
|
||||||
|
env.Program("^/typical.exe", glob("src/**/*.c"))
|
||||||
|
end
|
||||||
|
end
|
@ -1,9 +1,10 @@
|
|||||||
build do
|
build do
|
||||||
Environment.new(echo: :command) do |env|
|
Environment.new(echo: :command) do |env|
|
||||||
env.append('CPPPATH' => glob('src/**').sort)
|
env.append("CPPPATH" => glob("src/**"))
|
||||||
FileUtils.mkdir_p(env.build_root)
|
FileUtils.mkdir_p(env.build_root)
|
||||||
FileUtils.mv("src/one/one.c", env.build_root)
|
FileUtils.mv("src/one/one.c", env.build_root)
|
||||||
|
FileUtils.mv("src/two/two.c", Rscons.application.build_dir)
|
||||||
env.Object("^/one.o", "^/one.c")
|
env.Object("^/one.o", "^/one.c")
|
||||||
env.Program("program.exe", glob('src/**/*.c') + ["^/one.o"])
|
env.Program("^^/program.exe", ["^/one.o", "^^/two.c"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
9
build_tests/typical/clone_and_name.rb
Normal file
9
build_tests/typical/clone_and_name.rb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
build do
|
||||||
|
base_env = Environment.new do |env|
|
||||||
|
env["CPPPATH"] += glob("src/**")
|
||||||
|
end
|
||||||
|
|
||||||
|
base_env.clone(name: "typical") do |env|
|
||||||
|
env.Program("^/typical.exe", glob("src/**/*.c"))
|
||||||
|
end
|
||||||
|
end
|
11
build_tests/typical/fileutils_methods.rb
Normal file
11
build_tests/typical/fileutils_methods.rb
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
build do
|
||||||
|
mkdir "foo"
|
||||||
|
cd "foo" do
|
||||||
|
mkdir_p ["bar/baz", "bar/booz"]
|
||||||
|
end
|
||||||
|
mv "foo/bar", "foobar"
|
||||||
|
rmdir "foo"
|
||||||
|
touch "foobar/booz/a.txt"
|
||||||
|
cp "foobar/booz/a.txt", "foobar/baz/b.txt"
|
||||||
|
rm_rf "foobar/booz"
|
||||||
|
end
|
@ -78,10 +78,22 @@ cache file in order to avoid rebuilding a target when it is already up to date.
|
|||||||
### Build Directory
|
### Build Directory
|
||||||
|
|
||||||
Rscons was designed to store temporary build artifacts (for example, object
|
Rscons was designed to store temporary build artifacts (for example, object
|
||||||
files, dependency files, etc...) in a `build` directory.
|
files, dependency files, etc...) and build system metadata in a
|
||||||
|
"build directory".
|
||||||
This keeps files generated by the build cleanly separated from user-controlled
|
This keeps files generated by the build cleanly separated from user-controlled
|
||||||
source files.
|
source files.
|
||||||
|
|
||||||
|
In contrast to other build systems or build system generators, rscons executes
|
||||||
|
from the project base directory (up to the user) rather than executing from
|
||||||
|
*within* the build directory.
|
||||||
|
This keeps any file paths printed by compilers (such as in warning or error
|
||||||
|
messages) accurate relative to the project directory, so that the user does not
|
||||||
|
need to translate any paths to the correct path within a terminal or editor
|
||||||
|
application, for example.
|
||||||
|
|
||||||
|
By default a build directory named "build" is used, but this can be overridden
|
||||||
|
by the user by using the `-b`/`--build` command-line option.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
To use Rscons on your project, you must:
|
To use Rscons on your project, you must:
|
||||||
@ -94,7 +106,7 @@ To use Rscons on your project, you must:
|
|||||||
|
|
||||||
Rscons is designed to be distributed as a stand-alone single file script that
|
Rscons is designed to be distributed as a stand-alone single file script that
|
||||||
can be copied into and versioned in a project's source tree.
|
can be copied into and versioned in a project's source tree.
|
||||||
The only dependency required to run Rscons is to have a Ruby interpreter
|
The only requirement to run Rscons is that the system has a Ruby interpreter
|
||||||
installed.
|
installed.
|
||||||
The latest release can be downloaded from [https://github.com/holtrop/rscons/releases](https://github.com/holtrop/rscons/releases).
|
The latest release can be downloaded from [https://github.com/holtrop/rscons/releases](https://github.com/holtrop/rscons/releases).
|
||||||
Simply copy the `rscons` executable script into the desired location within
|
Simply copy the `rscons` executable script into the desired location within
|
||||||
@ -209,6 +221,171 @@ called `myprog.exe` which is to be built from all C source files found
|
|||||||
|
|
||||||
The `Rsconscript` file is a Ruby script.
|
The `Rsconscript` file is a Ruby script.
|
||||||
|
|
||||||
|
##> Build Script Methods
|
||||||
|
|
||||||
|
`rscons` provides several methods that a build script can use.
|
||||||
|
|
||||||
|
* `glob` (see ${#Finding Files: The glob Method})
|
||||||
|
* `path_append` (see ${#PATH Management})
|
||||||
|
* `path_components` (see ${#PATH Management})
|
||||||
|
* `path_prepend` (see ${#PATH Management})
|
||||||
|
* `path_set` (see ${#PATH Management})
|
||||||
|
* `rscons` (see ${#Using Subsidiary Build Scripts: The rscons Method})
|
||||||
|
* `sh` (see (${#Executing Commands: The sh Method})
|
||||||
|
|
||||||
|
Additionally, the following methods from the Ruby
|
||||||
|
[FileUtils](https://ruby-doc.org/stdlib-3.1.0/libdoc/fileutils/rdoc/FileUtils.html)
|
||||||
|
module are made available for the build script to call directly:
|
||||||
|
|
||||||
|
* `cd`
|
||||||
|
* `chmod`
|
||||||
|
* `chmod_R`
|
||||||
|
* `chown`
|
||||||
|
* `chown_R`
|
||||||
|
* `cp`
|
||||||
|
* `cp_lr`
|
||||||
|
* `cp_r`
|
||||||
|
* `install`
|
||||||
|
* `ln`
|
||||||
|
* `ln_s`
|
||||||
|
* `ln_sf`
|
||||||
|
* `mkdir`
|
||||||
|
* `mkdir_p`
|
||||||
|
* `mv`
|
||||||
|
* `pwd`
|
||||||
|
* `rm`
|
||||||
|
* `rm_f`
|
||||||
|
* `rm_r`
|
||||||
|
* `rm_rf`
|
||||||
|
* `rmdir`
|
||||||
|
* `touch`
|
||||||
|
|
||||||
|
###> Finding Files: The glob Method
|
||||||
|
|
||||||
|
The [`glob`](../yard/Rscons/Script/GlobalDsl.html#glob-instance_method) method can be
|
||||||
|
used to find files matching the patterns specified.
|
||||||
|
It supports a syntax similar to the Ruby [Dir.glob method](https://ruby-doc.org/core-3.1.0/Dir.html#method-c-glob) but operates more deterministically.
|
||||||
|
|
||||||
|
Example use:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.Program("mytests", glob("src/**/*.cc", "test/**/*.cc"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
This example would build the `mytests` executable from all `.cc` source files
|
||||||
|
found recursively under the `src` or `test` directory.
|
||||||
|
|
||||||
|
###> PATH Management
|
||||||
|
|
||||||
|
`rscons` provides methods for management of the `PATH` environment variable.
|
||||||
|
|
||||||
|
The
|
||||||
|
[`path_append`](../yard/Rscons/Script/GlobalDsl.html#path_append-instance_method)
|
||||||
|
and
|
||||||
|
[`path_prepend`](../yard/Rscons/Script/GlobalDsl.html#path_prepend-instance_method)
|
||||||
|
methods can be used to append or prepend a path to the `PATH` environment
|
||||||
|
variable.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
path_prepend "i686-elf-gcc/bin"
|
||||||
|
```
|
||||||
|
|
||||||
|
The
|
||||||
|
[`path_set`](../yard/Rscons/Script/GlobalDsl.html#path_set-instance_method)
|
||||||
|
method sets the `PATH` environment variable to the given Array or String.
|
||||||
|
|
||||||
|
The
|
||||||
|
[`path_components`](../yard/Rscons/Script/GlobalDsl.html#path_components-instance_method)
|
||||||
|
method returns an Array of the components in the `PATH`
|
||||||
|
environment variable.
|
||||||
|
|
||||||
|
###> Using Subsidiary Build Scripts: The rscons Method
|
||||||
|
|
||||||
|
The
|
||||||
|
[`rscons`](../yard/Rscons/Script/GlobalDsl.html#rscons-instance_method)
|
||||||
|
build script method can be used to invoke an rscons subprocess to
|
||||||
|
perform an operation using a subsidiary rscons build script.
|
||||||
|
This can be used, for example, when a subproject is imported and a top-level
|
||||||
|
`configure` or `build` operation should also perform the same operation in the
|
||||||
|
subproject directory.
|
||||||
|
|
||||||
|
The first argument to the `rscons` method specifies either a directory name, or
|
||||||
|
the path to the subsidiary Rsconscript file to execute.
|
||||||
|
Any additional arguments are passed to `rscons` when it executes the subsidiary
|
||||||
|
script.
|
||||||
|
`rscons` will change working directories to the directory containing the
|
||||||
|
subsidiary script when executing it.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
configure do
|
||||||
|
rscons "subproject", "configure"
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
rscons "subproject/Rsconscript", "build"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
It is also perfectly valid to perform a different operation in the subsidiary
|
||||||
|
script from the one being performed in the top-level script.
|
||||||
|
For example, in a project that requires a particular cross compiler, the
|
||||||
|
top-level `configure` script could build the necessary cross compiler using a
|
||||||
|
subsidiary build script.
|
||||||
|
This could look something like:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
configure do
|
||||||
|
rscons "cross/Rsconscript"
|
||||||
|
check_c_compiler "i686-elf-gcc"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
This would build, and if necessary first configure, using the cross/Rsconscript
|
||||||
|
subsidiary build script.
|
||||||
|
Subsidiary build scripts are executed from within the directory containing the
|
||||||
|
build script.
|
||||||
|
|
||||||
|
###> Executing Commands: The sh Method
|
||||||
|
|
||||||
|
The
|
||||||
|
[`sh`](../yard/Rscons/Script/GlobalDsl.html#sh-instance_method)
|
||||||
|
build script method can be used to directly execute commands.
|
||||||
|
The `sh` method accepts either a single String argument or an Array of Strings.
|
||||||
|
When an Array is given, if the array length is greater than 1, then the command
|
||||||
|
will not be executed and interpreted by the system shell.
|
||||||
|
Otherwise, it will be executed and interpreted by the system shell.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
build do
|
||||||
|
# Run "make" in imported "subcomponent" directory.
|
||||||
|
sh "cd subcomponent; make"
|
||||||
|
# Move a file around.
|
||||||
|
sh "mv", "subcomponent/file with spaces.txt", "new_name.txt"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
If the command fails, rscons will normally print the error and terminate
|
||||||
|
execution.
|
||||||
|
If the `:continue` option is set, then rscons will not terminate execution.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
build do
|
||||||
|
# This command will fail and a message will be printed.
|
||||||
|
sh "false", continue: true
|
||||||
|
# However, due to the :continue option being set, execution will continue.
|
||||||
|
sh "echo hi"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
##> Configuration Operations
|
##> Configuration Operations
|
||||||
|
|
||||||
A `configure` block is optional.
|
A `configure` block is optional.
|
||||||
@ -492,21 +669,26 @@ source files found recursively under the `src` directory.
|
|||||||
|
|
||||||
An Environment includes:
|
An Environment includes:
|
||||||
|
|
||||||
|
- a name
|
||||||
- a collection of construction variables
|
- a collection of construction variables
|
||||||
- a collection of build hooks
|
- a collection of build hooks
|
||||||
- a collection of user-registered build targets
|
- a collection of user-registered build targets
|
||||||
- a build root
|
- a build root
|
||||||
|
|
||||||
All build targets must be registered within an `Environment`.
|
All build targets must be registered within an `Environment`.
|
||||||
|
If the user does not specify a name for the environment, a name will be
|
||||||
|
automatically generated based on the Environment's internal ID, for example
|
||||||
|
"e.1".
|
||||||
The Environment's build root is a directory created within the top-level
|
The Environment's build root is a directory created within the top-level
|
||||||
Rscons build directory.
|
Rscons build directory.
|
||||||
|
It is based on the Environment name.
|
||||||
By default it holds all intermediate files generated by Rscons that are needed
|
By default it holds all intermediate files generated by Rscons that are needed
|
||||||
to produce a user-specified build target.
|
to produce a user-specified build target.
|
||||||
For example, for the `Rsconscript`:
|
For example, for the `Rsconscript`:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
build do
|
build do
|
||||||
Environment.new do |env|
|
Environment.new(name: "myproj") do |env|
|
||||||
env.Program("myprog.exe", glob("src/**/*.c"))
|
env.Program("myprog.exe", glob("src/**/*.c"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -514,28 +696,11 @@ end
|
|||||||
|
|
||||||
Rscons will place an object file and dependency file corresponding to each C
|
Rscons will place an object file and dependency file corresponding to each C
|
||||||
source file under the Environment's build root.
|
source file under the Environment's build root.
|
||||||
|
Assuming a top-level build directory of "build", the Environment's build root
|
||||||
|
would be "build/myproj".
|
||||||
This keeps the intermediate generated build artifacts separate from the source
|
This keeps the intermediate generated build artifacts separate from the source
|
||||||
files.
|
files.
|
||||||
|
|
||||||
###> Specifying Source Files: The glob Method
|
|
||||||
|
|
||||||
The [`glob`](../yard/Rscons/Script/Dsl.html#glob-instance_method) method can be
|
|
||||||
used to find files matching the patterns specified.
|
|
||||||
It supports a syntax similar to the Ruby [Dir.glob method](https://ruby-doc.org/core-2.5.1/Dir.html#method-c-glob) but operates more deterministically.
|
|
||||||
|
|
||||||
Example use:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
build do
|
|
||||||
Environment.new do |env|
|
|
||||||
env.Program("mytests", glob("src/**/*.cc", "test/**/*.cc"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
This example would build the `mytests` executable from all `.cc` source files
|
|
||||||
found recursively under the `src` or `test` directory.
|
|
||||||
|
|
||||||
###> Construction Variables
|
###> Construction Variables
|
||||||
|
|
||||||
Construction variables are values assigned to keys within an Environment.
|
Construction variables are values assigned to keys within an Environment.
|
||||||
@ -606,6 +771,7 @@ There are several default builders that are built-in to Rscons:
|
|||||||
library.
|
library.
|
||||||
* `SharedObject`, which compiles source files to produce an object file, in a
|
* `SharedObject`, which compiles source files to produce an object file, in a
|
||||||
way that is able to be used to create a shared library.
|
way that is able to be used to create a shared library.
|
||||||
|
* `Size`, which runs the 'size' utility on an executable file.
|
||||||
|
|
||||||
####> The Command Builder
|
####> The Command Builder
|
||||||
|
|
||||||
@ -821,6 +987,20 @@ allows it to be used to create a shared library are added.
|
|||||||
Although it can be called explicitly, it is more commonly implicitly called by
|
Although it can be called explicitly, it is more commonly implicitly called by
|
||||||
the `SharedLibrary` builder.
|
the `SharedLibrary` builder.
|
||||||
|
|
||||||
|
####> The Size Builder
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
env.Size(target, sources)
|
||||||
|
# Example
|
||||||
|
env.Program("program.exe", glob("*.c"))
|
||||||
|
env.Size("program.size", "program.exe")
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Size` builder runs the "size" executable on the given source file and
|
||||||
|
stores its output in the target file.
|
||||||
|
The size executable can be specified with the `SIZE` construction variable,
|
||||||
|
and flags can be specified with `SIZEFLAGS`.
|
||||||
|
|
||||||
###> Phony Targets
|
###> Phony Targets
|
||||||
|
|
||||||
rscons supports phony build targets.
|
rscons supports phony build targets.
|
||||||
@ -900,70 +1080,6 @@ In other words, build targets are not parallelized across a barrier.
|
|||||||
env.barrier
|
env.barrier
|
||||||
```
|
```
|
||||||
|
|
||||||
##> Global Build Script Functionality
|
|
||||||
|
|
||||||
###> Using Subsidiary Build Scripts
|
|
||||||
|
|
||||||
The `rscons` build script method can be used to invoke an rscons subprocess to
|
|
||||||
perform an operation using a subsidiary rscons build script.
|
|
||||||
This can be used, for example, when a subproject is imported and a top-level
|
|
||||||
`configure` or `build` operation should also perform the same operation in the
|
|
||||||
subproject directory.
|
|
||||||
|
|
||||||
The first argument to the `rscons` method specifies either a directory name, or
|
|
||||||
the path to the subsidiary Rsconscript file to execute.
|
|
||||||
Any additional arguments are passed to `rscons` when it executes the subsidiary
|
|
||||||
script.
|
|
||||||
`rscons` will change working directories to the directory containing the
|
|
||||||
subsidiary script when executing it.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
configure do
|
|
||||||
rscons "subproject", "configure"
|
|
||||||
end
|
|
||||||
|
|
||||||
build do
|
|
||||||
rscons "subproject/Rsconscript", "build"
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
It is also perfectly valid to perform a different operation in the subsidiary
|
|
||||||
script from the one being performed in the top-level script.
|
|
||||||
For example, in a project that requires a particular cross compiler, the
|
|
||||||
top-level `configure` script could build the necessary cross compiler using a
|
|
||||||
subsidiary build script.
|
|
||||||
This could look something like:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
configure do
|
|
||||||
rscons "cross/Rsconscript"
|
|
||||||
check_c_compiler "i686-elf-gcc"
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
This would build, and if necessary first configure, using the cross/Rsconscript
|
|
||||||
subsidiary build script.
|
|
||||||
Subsidiary build scripts are executed from within the directory containing the
|
|
||||||
build script.
|
|
||||||
|
|
||||||
###> PATH Management
|
|
||||||
|
|
||||||
`rscons` provides methods for management of the `PATH` environment variable.
|
|
||||||
|
|
||||||
The `path_append` and `path_prepend` methods can be used to append or prepend
|
|
||||||
a path to the `PATH` environment variable.
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
path_prepend "i686-elf-gcc/bin"
|
|
||||||
```
|
|
||||||
|
|
||||||
The `path_set` method sets the `PATH` environment variable to the given
|
|
||||||
Array or String.
|
|
||||||
The `path_components` method returns an Array of the components in the `PATH`
|
|
||||||
environment variable.
|
|
||||||
|
|
||||||
##> Extending Rscons
|
##> Extending Rscons
|
||||||
|
|
||||||
### Adding New Languages
|
### Adding New Languages
|
||||||
|
@ -33,6 +33,7 @@ module Rscons
|
|||||||
:Program,
|
:Program,
|
||||||
:SharedLibrary,
|
:SharedLibrary,
|
||||||
:SharedObject,
|
:SharedObject,
|
||||||
|
:Size,
|
||||||
]
|
]
|
||||||
|
|
||||||
# Class to represent a fatal error during an Rscons operation.
|
# Class to represent a fatal error during an Rscons operation.
|
||||||
@ -146,6 +147,7 @@ require_relative "rscons/builders/program"
|
|||||||
require_relative "rscons/builders/shared_library"
|
require_relative "rscons/builders/shared_library"
|
||||||
require_relative "rscons/builders/shared_object"
|
require_relative "rscons/builders/shared_object"
|
||||||
require_relative "rscons/builders/simple_builder"
|
require_relative "rscons/builders/simple_builder"
|
||||||
|
require_relative "rscons/builders/size"
|
||||||
|
|
||||||
# language support
|
# language support
|
||||||
require_relative "rscons/builders/lang/asm"
|
require_relative "rscons/builders/lang/asm"
|
||||||
|
@ -5,6 +5,10 @@ module Rscons
|
|||||||
# Functionality for an instance of the rscons application invocation.
|
# Functionality for an instance of the rscons application invocation.
|
||||||
class Application
|
class Application
|
||||||
|
|
||||||
|
# @return [String]
|
||||||
|
# Top-level build directory.
|
||||||
|
attr_accessor :build_dir
|
||||||
|
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
# Whether to output ANSI color escape sequences.
|
# Whether to output ANSI color escape sequences.
|
||||||
attr_accessor :do_ansi_color
|
attr_accessor :do_ansi_color
|
||||||
@ -23,6 +27,8 @@ module Rscons
|
|||||||
|
|
||||||
# Create Application instance.
|
# Create Application instance.
|
||||||
def initialize
|
def initialize
|
||||||
|
@build_dir = ENV["RSCONS_BUILD_DIR"] || "build"
|
||||||
|
ENV.delete("RSCONS_BUILD_DIR")
|
||||||
@n_threads = Util.determine_n_threads
|
@n_threads = Util.determine_n_threads
|
||||||
@vars = VarSet.new
|
@vars = VarSet.new
|
||||||
@operations = Set.new
|
@operations = Set.new
|
||||||
@ -171,11 +177,8 @@ module Rscons
|
|||||||
# Exit code.
|
# Exit code.
|
||||||
def distclean
|
def distclean
|
||||||
cache = Cache.instance
|
cache = Cache.instance
|
||||||
build_dir = cache["configuration_data"]["build_dir"]
|
|
||||||
clean
|
clean
|
||||||
if build_dir
|
FileUtils.rm_rf(@build_dir)
|
||||||
FileUtils.rm_rf(build_dir)
|
|
||||||
end
|
|
||||||
cache.clear
|
cache.clear
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
24
lib/rscons/builders/size.rb
Normal file
24
lib/rscons/builders/size.rb
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module Rscons
|
||||||
|
module Builders
|
||||||
|
# Run the "size" utility on an executable and store its results in the
|
||||||
|
# target file.
|
||||||
|
# input file.
|
||||||
|
#
|
||||||
|
# Examples::
|
||||||
|
# env.Size("^/project.size", "^/project.elf")
|
||||||
|
class Size < Builder
|
||||||
|
|
||||||
|
# Run the builder to produce a build target.
|
||||||
|
def run(options)
|
||||||
|
if @command
|
||||||
|
finalize_command
|
||||||
|
else
|
||||||
|
@vars["_SOURCES"] = @sources
|
||||||
|
command = @env.build_command("${SIZECMD}", @vars)
|
||||||
|
standard_command("Size <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command, stdout: @target)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -51,9 +51,6 @@ module Rscons
|
|||||||
# }
|
# }
|
||||||
class Cache
|
class Cache
|
||||||
|
|
||||||
# Name of the file to store cache information in
|
|
||||||
CACHE_FILE = ".rsconscache"
|
|
||||||
|
|
||||||
# Prefix for phony cache entries.
|
# Prefix for phony cache entries.
|
||||||
PHONY_PREFIX = ":PHONY:"
|
PHONY_PREFIX = ":PHONY:"
|
||||||
|
|
||||||
@ -70,6 +67,11 @@ module Rscons
|
|||||||
initialize!
|
initialize!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Get the path to the cache file.
|
||||||
|
def cache_file
|
||||||
|
File.join(Rscons.application.build_dir, ".rsconscache")
|
||||||
|
end
|
||||||
|
|
||||||
# Access cache value.
|
# Access cache value.
|
||||||
def [](key)
|
def [](key)
|
||||||
@cache[key]
|
@cache[key]
|
||||||
@ -84,7 +86,7 @@ module Rscons
|
|||||||
#
|
#
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def clear
|
def clear
|
||||||
FileUtils.rm_f(CACHE_FILE)
|
FileUtils.rm_f(cache_file)
|
||||||
initialize!
|
initialize!
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -100,7 +102,7 @@ module Rscons
|
|||||||
# @return [void]
|
# @return [void]
|
||||||
def write
|
def write
|
||||||
@cache["version"] = VERSION
|
@cache["version"] = VERSION
|
||||||
File.open(CACHE_FILE, "w") do |fh|
|
File.open(cache_file, "w") do |fh|
|
||||||
fh.puts(JSON.dump(@cache))
|
fh.puts(JSON.dump(@cache))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -360,9 +362,9 @@ module Rscons
|
|||||||
# Create a Cache object and load in the previous contents from the cache
|
# Create a Cache object and load in the previous contents from the cache
|
||||||
# file.
|
# file.
|
||||||
def initialize!
|
def initialize!
|
||||||
@cache = JSON.load(File.read(CACHE_FILE)) rescue {}
|
@cache = JSON.load(File.read(cache_file)) rescue {}
|
||||||
unless @cache.is_a?(Hash)
|
unless @cache.is_a?(Hash)
|
||||||
$stderr.puts "Warning: #{CACHE_FILE} was corrupt. Contents:\n#{@cache.inspect}"
|
$stderr.puts "Warning: #{cache_file} was corrupt. Contents:\n#{@cache.inspect}"
|
||||||
@cache = {}
|
@cache = {}
|
||||||
end
|
end
|
||||||
@cache["targets"] ||= {}
|
@cache["targets"] ||= {}
|
||||||
|
@ -6,6 +6,7 @@ USAGE = <<EOF
|
|||||||
Usage: #{$0} [global options] [operation] [operation options]
|
Usage: #{$0} [global options] [operation] [operation options]
|
||||||
|
|
||||||
Global options:
|
Global options:
|
||||||
|
-b BUILD, --build=BUILD Set build directory (default: build)
|
||||||
-f FILE Use FILE as Rsconscript
|
-f FILE Use FILE as Rsconscript
|
||||||
-F, --show-failure Show failed command log from previous build and exit
|
-F, --show-failure Show failed command log from previous build and exit
|
||||||
-h, --help Show rscons help and exit
|
-h, --help Show rscons help and exit
|
||||||
@ -23,7 +24,6 @@ Operations:
|
|||||||
uninstall Uninstall project from installation destination
|
uninstall Uninstall project from installation destination
|
||||||
|
|
||||||
Configure options:
|
Configure options:
|
||||||
-b BUILD, --build=BUILD Set build directory (default: build)
|
|
||||||
--prefix=PREFIX Set installation prefix (default: /usr/local)
|
--prefix=PREFIX Set installation prefix (default: /usr/local)
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
@ -56,6 +56,10 @@ module Rscons
|
|||||||
private
|
private
|
||||||
|
|
||||||
def add_global_options(opts)
|
def add_global_options(opts)
|
||||||
|
opts.on("-b", "--build DIR") do |build_dir|
|
||||||
|
Rscons.application.build_dir = build_dir
|
||||||
|
end
|
||||||
|
|
||||||
opts.on("-j NTHREADS") do |n_threads|
|
opts.on("-j NTHREADS") do |n_threads|
|
||||||
Rscons.application.n_threads = n_threads.to_i
|
Rscons.application.n_threads = n_threads.to_i
|
||||||
end
|
end
|
||||||
@ -156,10 +160,6 @@ module Rscons
|
|||||||
end
|
end
|
||||||
|
|
||||||
def parse_configure_args(opts, argv, options)
|
def parse_configure_args(opts, argv, options)
|
||||||
opts.on("-b", "--build DIR") do |build_dir|
|
|
||||||
options[:build_dir] = build_dir
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on("--prefix PREFIX") do |prefix|
|
opts.on("--prefix PREFIX") do |prefix|
|
||||||
options[:prefix] = prefix
|
options[:prefix] = prefix
|
||||||
end
|
end
|
||||||
|
@ -9,30 +9,25 @@ module Rscons
|
|||||||
#
|
#
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# Optional parameters.
|
# Optional parameters.
|
||||||
# @option options [String] :build_dir
|
|
||||||
# Build directory.
|
|
||||||
# @option options [String] :prefix
|
# @option options [String] :prefix
|
||||||
# Install prefix.
|
# Install prefix.
|
||||||
# @option options [String] :project_name
|
# @option options [String] :project_name
|
||||||
# Project name.
|
# Project name.
|
||||||
def initialize(options)
|
def initialize(options)
|
||||||
# Default options.
|
# Default options.
|
||||||
options[:build_dir] ||= "build"
|
|
||||||
options[:prefix] ||= "/usr/local"
|
options[:prefix] ||= "/usr/local"
|
||||||
@work_dir = "#{options[:build_dir]}/configure"
|
@work_dir = "#{Rscons.application.build_dir}/_configure"
|
||||||
FileUtils.mkdir_p(@work_dir)
|
FileUtils.mkdir_p(@work_dir)
|
||||||
@log_fh = File.open("#{@work_dir}/config.log", "wb")
|
@log_fh = File.open("#{@work_dir}/config.log", "wb")
|
||||||
cache = Cache.instance
|
cache = Cache.instance
|
||||||
cache["failed_commands"] = []
|
cache["failed_commands"] = []
|
||||||
cache["configuration_data"] = {}
|
cache["configuration_data"] = {}
|
||||||
cache["configuration_data"]["build_dir"] = options[:build_dir]
|
|
||||||
cache["configuration_data"]["prefix"] = options[:prefix]
|
cache["configuration_data"]["prefix"] = options[:prefix]
|
||||||
if project_name = options[:project_name]
|
if project_name = options[:project_name]
|
||||||
Ansi.write($stdout, "Configuring ", :cyan, project_name, :reset, "...\n")
|
Ansi.write($stdout, "Configuring ", :cyan, project_name, :reset, "...\n")
|
||||||
else
|
else
|
||||||
$stdout.puts "Configuring project..."
|
$stdout.puts "Configuring project..."
|
||||||
end
|
end
|
||||||
Ansi.write($stdout, "Setting build directory... ", :green, options[:build_dir], :reset, "\n")
|
|
||||||
Ansi.write($stdout, "Setting prefix... ", :green, options[:prefix], :reset, "\n")
|
Ansi.write($stdout, "Setting prefix... ", :green, options[:prefix], :reset, "\n")
|
||||||
store_merge("prefix" => options[:prefix])
|
store_merge("prefix" => options[:prefix])
|
||||||
end
|
end
|
||||||
|
@ -80,6 +80,9 @@ module Rscons
|
|||||||
"SHLIBLINKPREFIX" => "-l",
|
"SHLIBLINKPREFIX" => "-l",
|
||||||
"SHLIBPREFIX" => on_windows ? "" : "lib",
|
"SHLIBPREFIX" => on_windows ? "" : "lib",
|
||||||
"SHLIBSUFFIX" => on_windows ? ".dll" : ".so",
|
"SHLIBSUFFIX" => on_windows ? ".dll" : ".so",
|
||||||
|
"SIZE" => "size",
|
||||||
|
"SIZECMD" => %w[${SIZE} ${SIZEFLAGS} ${_SOURCES}],
|
||||||
|
"SIZEFLAGS" => [],
|
||||||
"YACC" => "bison",
|
"YACC" => "bison",
|
||||||
"YACCSUFFIX" => %w[.y .yy],
|
"YACCSUFFIX" => %w[.y .yy],
|
||||||
"YACC_CMD" => %w[${YACC} ${YACC_FLAGS} -o ${_TARGET} ${_SOURCES}],
|
"YACC_CMD" => %w[${YACC} ${YACC_FLAGS} -o ${_TARGET} ${_SOURCES}],
|
||||||
|
@ -51,6 +51,10 @@ module Rscons
|
|||||||
# global Rscons.application.n_threads value.
|
# global Rscons.application.n_threads value.
|
||||||
attr_accessor :n_threads
|
attr_accessor :n_threads
|
||||||
|
|
||||||
|
# @return [String]
|
||||||
|
# Environment name.
|
||||||
|
attr_reader :name
|
||||||
|
|
||||||
# Create an Environment object.
|
# Create an Environment object.
|
||||||
#
|
#
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
@ -58,6 +62,9 @@ module Rscons
|
|||||||
# :command, :short, or :off (default :short)
|
# :command, :short, or :off (default :short)
|
||||||
# @option options [Boolean] :exclude_builders
|
# @option options [Boolean] :exclude_builders
|
||||||
# Whether to omit adding default builders (default false)
|
# Whether to omit adding default builders (default false)
|
||||||
|
# @option options [String, nil] :name
|
||||||
|
# Environment name. This determines the folder name used to store all
|
||||||
|
# environment build files under the top-level build directory.
|
||||||
# @option options [String, Array<String>] :use
|
# @option options [String, Array<String>] :use
|
||||||
# Use flag(s). If specified, any configuration flags which were saved
|
# Use flag(s). If specified, any configuration flags which were saved
|
||||||
# with a corresponding `:use` value will be applied to this Environment.
|
# with a corresponding `:use` value will be applied to this Environment.
|
||||||
@ -97,7 +104,8 @@ module Rscons
|
|||||||
else
|
else
|
||||||
:short
|
:short
|
||||||
end
|
end
|
||||||
@build_root = "#{Cache.instance["configuration_data"]["build_dir"]}/e.#{@id}"
|
@name = options[:name] || "e.#{@id}"
|
||||||
|
@build_root = "#{Rscons.application.build_dir}/#{@name}"
|
||||||
@n_threads = Rscons.application.n_threads
|
@n_threads = Rscons.application.n_threads
|
||||||
|
|
||||||
if block_given?
|
if block_given?
|
||||||
@ -125,14 +133,14 @@ module Rscons
|
|||||||
#
|
#
|
||||||
# @return [Environment] The newly created {Environment} object.
|
# @return [Environment] The newly created {Environment} object.
|
||||||
def clone(options = {})
|
def clone(options = {})
|
||||||
|
options = options.dup
|
||||||
clone = options[:clone] || :all
|
clone = options[:clone] || :all
|
||||||
clone = Set[:variables, :builders, :build_hooks] if clone == :all
|
clone = Set[:variables, :builders, :build_hooks] if clone == :all
|
||||||
clone = Set[] if clone == :none
|
clone = Set[] if clone == :none
|
||||||
clone = Set.new(clone) if clone.is_a?(Array)
|
clone = Set.new(clone) if clone.is_a?(Array)
|
||||||
clone.delete(:builders) if options[:exclude_builders]
|
clone.delete(:builders) if options[:exclude_builders]
|
||||||
env = self.class.new(
|
options[:echo] ||= @echo
|
||||||
echo: options[:echo] || @echo,
|
env = self.class.new(options.merge(exclude_builders: true))
|
||||||
exclude_builders: true)
|
|
||||||
if clone.include?(:builders)
|
if clone.include?(:builders)
|
||||||
@builders.each do |builder_name, builder|
|
@builders.each do |builder_name, builder|
|
||||||
env.add_builder(builder)
|
env.add_builder(builder)
|
||||||
@ -467,10 +475,12 @@ module Rscons
|
|||||||
output_fname
|
output_fname
|
||||||
end
|
end
|
||||||
|
|
||||||
# Expand a path to be relative to the Environment's build root.
|
# Expand paths.
|
||||||
#
|
#
|
||||||
# Paths beginning with "^/" are expanded by replacing "^" with the
|
# Paths beginning with "^/" are expanded by replacing "^" with the
|
||||||
# Environment's build root.
|
# Environment's build root (e.g. "build/envname").
|
||||||
|
# Paths beginning with "^^/" are expanded by replacing "^^" with the
|
||||||
|
# top-level build directory (e.g. "build").
|
||||||
#
|
#
|
||||||
# @param path [String, Array<String>]
|
# @param path [String, Array<String>]
|
||||||
# The path(s) to expand.
|
# The path(s) to expand.
|
||||||
@ -485,7 +495,7 @@ module Rscons
|
|||||||
expand_path(path)
|
expand_path(path)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
path.sub(%r{^\^(?=[\\/])}, @build_root).gsub("\\", "/")
|
path.sub(%r{^\^\^(?=[\\/])}, Rscons.application.build_dir).sub(%r{^\^(?=[\\/])}, @build_root).gsub("\\", "/")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -6,6 +6,33 @@ module Rscons
|
|||||||
# Global DSL methods.
|
# Global DSL methods.
|
||||||
class GlobalDsl
|
class GlobalDsl
|
||||||
|
|
||||||
|
# Return a list of paths matching the specified pattern(s).
|
||||||
|
#
|
||||||
|
# A pattern can contain a "/**" component to recurse through directories.
|
||||||
|
# If the pattern ends with "/**" then only the recursive list of
|
||||||
|
# directories will be returned.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# - "src/**": return all directories under "src", recursively (including
|
||||||
|
# "src" itself).
|
||||||
|
# - "src/**/*": return all files and directories recursively under the src
|
||||||
|
# directory.
|
||||||
|
# - "src/**/*.c": return all .c files recursively under the src directory.
|
||||||
|
# - "dir/*/": return all directories in dir, but no files.
|
||||||
|
#
|
||||||
|
# @return [Array<String>] Paths matching the specified pattern(s).
|
||||||
|
def glob(*patterns)
|
||||||
|
require "pathname"
|
||||||
|
patterns.reduce([]) do |result, pattern|
|
||||||
|
if pattern.end_with?("/**")
|
||||||
|
pattern += "/"
|
||||||
|
end
|
||||||
|
result += Dir.glob(pattern).map do |path|
|
||||||
|
Pathname.new(path.gsub("\\", "/")).cleanpath.to_s
|
||||||
|
end
|
||||||
|
end.sort
|
||||||
|
end
|
||||||
|
|
||||||
# Return path components from the PATH variable.
|
# Return path components from the PATH variable.
|
||||||
#
|
#
|
||||||
# @return [Array<String>]
|
# @return [Array<String>]
|
||||||
@ -80,6 +107,87 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Execute a shell command, exiting on failure.
|
||||||
|
# The behavior to exit on failure is suppressed if the +:continue+
|
||||||
|
# option is given.
|
||||||
|
#
|
||||||
|
# @overload sh(command, options = {})
|
||||||
|
# @param command [String, Array<String>]
|
||||||
|
# Command to execute. The command is executed and interpreted by the
|
||||||
|
# system shell when given as a single string. It is not passed to the
|
||||||
|
# system shell if the array size is greater than 1.
|
||||||
|
# @param options [Hash]
|
||||||
|
# Options.
|
||||||
|
# @option options [Boolean] :continue
|
||||||
|
# If set to +true+, rscons will continue executing afterward, even if
|
||||||
|
# the command fails.
|
||||||
|
#
|
||||||
|
# @overload sh(*command, options = {})
|
||||||
|
# @param command [String, Array<String>]
|
||||||
|
# Command to execute. The command is executed and interpreted by the
|
||||||
|
# system shell when given as a single string. It is not passed to the
|
||||||
|
# system shell if the array size is greater than 1.
|
||||||
|
# @param options [Hash]
|
||||||
|
# Options.
|
||||||
|
# @option options [Boolean] :continue
|
||||||
|
# If set to +true+, rscons will continue executing afterward, even if
|
||||||
|
# the command fails.
|
||||||
|
def sh(*command)
|
||||||
|
options = {}
|
||||||
|
if command.last.is_a?(Hash)
|
||||||
|
options = command.slice!(-1)
|
||||||
|
end
|
||||||
|
if command.size == 1 && command[0].is_a?(Array)
|
||||||
|
command = command[0]
|
||||||
|
end
|
||||||
|
if Rscons.application.verbose
|
||||||
|
if command.size > 1
|
||||||
|
puts Util.command_to_s(command)
|
||||||
|
else
|
||||||
|
puts command[0]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
begin
|
||||||
|
system(*command, exception: true)
|
||||||
|
rescue StandardError => e
|
||||||
|
message = "#{e.backtrace[2]}: #{e.message}"
|
||||||
|
if options[:continue]
|
||||||
|
Ansi.write($stderr, :red, message, :reset, "\n")
|
||||||
|
else
|
||||||
|
raise RsconsError.new(message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
[
|
||||||
|
:cd,
|
||||||
|
:chmod,
|
||||||
|
:chmod_R,
|
||||||
|
:chown,
|
||||||
|
:chown_R,
|
||||||
|
:cp,
|
||||||
|
:cp_lr,
|
||||||
|
:cp_r,
|
||||||
|
:install,
|
||||||
|
:ln,
|
||||||
|
:ln_s,
|
||||||
|
:ln_sf,
|
||||||
|
:mkdir,
|
||||||
|
:mkdir_p,
|
||||||
|
:mv,
|
||||||
|
:pwd,
|
||||||
|
:rm,
|
||||||
|
:rm_f,
|
||||||
|
:rm_r,
|
||||||
|
:rm_rf,
|
||||||
|
:rmdir,
|
||||||
|
:touch,
|
||||||
|
].each do |method|
|
||||||
|
define_method(method) do |*args, **kwargs, &block|
|
||||||
|
FileUtils.__send__(method, *args, **kwargs, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Top-level DSL available to the Rsconscript.
|
# Top-level DSL available to the Rsconscript.
|
||||||
@ -108,33 +216,6 @@ module Rscons
|
|||||||
def configure(&block)
|
def configure(&block)
|
||||||
@script.operations["configure"] = block
|
@script.operations["configure"] = block
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return a list of paths matching the specified pattern(s).
|
|
||||||
#
|
|
||||||
# A pattern can contain a "/**" component to recurse through directories.
|
|
||||||
# If the pattern ends with "/**" then only the recursive list of
|
|
||||||
# directories will be returned.
|
|
||||||
#
|
|
||||||
# Examples:
|
|
||||||
# - "src/**": return all directories under "src", recursively (including
|
|
||||||
# "src" itself).
|
|
||||||
# - "src/**/*": return all files and directories recursively under the src
|
|
||||||
# directory.
|
|
||||||
# - "src/**/*.c": return all .c files recursively under the src directory.
|
|
||||||
# - "dir/*/": return all directories in dir, but no files.
|
|
||||||
#
|
|
||||||
# @return [Array<String>] Paths matching the specified pattern(s).
|
|
||||||
def glob(*patterns)
|
|
||||||
require "pathname"
|
|
||||||
patterns.reduce([]) do |result, pattern|
|
|
||||||
if pattern.end_with?("/**")
|
|
||||||
pattern += "/"
|
|
||||||
end
|
|
||||||
result += Dir.glob(pattern).map do |path|
|
|
||||||
Pathname.new(path.gsub("\\", "/")).cleanpath.to_s
|
|
||||||
end
|
|
||||||
end.sort
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# DSL available to the 'configure' block.
|
# DSL available to the 'configure' block.
|
||||||
|
@ -48,7 +48,7 @@ module Rscons
|
|||||||
# @return [String]
|
# @return [String]
|
||||||
# The string representation of the command.
|
# The string representation of the command.
|
||||||
def command_to_s(command)
|
def command_to_s(command)
|
||||||
command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ')
|
command.map { |c| c[" "] ? "'#{c.gsub("'", "'\\\\''")}'" : c }.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Determine the number of threads to use by default.
|
# Determine the number of threads to use by default.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
module Rscons
|
module Rscons
|
||||||
# Project version.
|
# Project version.
|
||||||
VERSION = "2.2.0"
|
VERSION = "2.3.0"
|
||||||
end
|
end
|
||||||
|
@ -66,6 +66,7 @@ compressed_script = Zlib::Deflate.deflate(stripped.join)
|
|||||||
encoded_compressed_script = Base64.encode64(compressed_script).gsub("\n", "")
|
encoded_compressed_script = Base64.encode64(compressed_script).gsub("\n", "")
|
||||||
hash = Digest::MD5.hexdigest(encoded_compressed_script)
|
hash = Digest::MD5.hexdigest(encoded_compressed_script)
|
||||||
|
|
||||||
|
FileUtils.rm_rf(DIST)
|
||||||
FileUtils.mkdir_p(DIST)
|
FileUtils.mkdir_p(DIST)
|
||||||
File.open("#{DIST}/#{PROG_NAME}", "wb", 0755) do |fh|
|
File.open("#{DIST}/#{PROG_NAME}", "wb", 0755) do |fh|
|
||||||
fh.write(<<EOF)
|
fh.write(<<EOF)
|
||||||
|
@ -208,6 +208,23 @@ EOF
|
|||||||
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
|
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "uses the build directory specified with -b" do
|
||||||
|
test_dir("simple")
|
||||||
|
result = run_rscons(rscons_args: %w[-b b])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(Dir.exist?("build")).to be_falsey
|
||||||
|
expect(File.exists?("b/e.1/simple.c.o")).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses the build directory specified by an environment variable" do
|
||||||
|
test_dir("simple")
|
||||||
|
passenv["RSCONS_BUILD_DIR"] = "b2"
|
||||||
|
result = run_rscons
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(Dir.exist?("build")).to be_falsey
|
||||||
|
expect(File.exists?("b2/e.1/simple.c.o")).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
it "allows specifying a Builder object as the source to another build target" do
|
it "allows specifying a Builder object as the source to another build target" do
|
||||||
test_dir("simple")
|
test_dir("simple")
|
||||||
result = run_rscons(rsconscript: "builder_as_source.rb")
|
result = run_rscons(rsconscript: "builder_as_source.rb")
|
||||||
@ -321,14 +338,14 @@ EOF
|
|||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "expands target and source paths starting with ^/ to be relative to the build root" do
|
it "expands target and source paths starting with ^/ and ^^/" do
|
||||||
test_dir("typical")
|
test_dir("typical")
|
||||||
result = run_rscons(rsconscript: "carat.rb")
|
result = run_rscons(rsconscript: "carat.rb", rscons_args: %w[-b bld])
|
||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
verify_lines(lines(result.stdout), [
|
verify_lines(lines(result.stdout), [
|
||||||
%r{gcc -c -o build/e.1/one.o -MMD -MF build/e.1/one.o.mf -Isrc -Isrc/one -Isrc/two build/e.1/one.c},
|
%r{gcc -c -o bld/e.1/one.o -MMD -MF bld/e.1/one.o.mf -Isrc -Isrc/one -Isrc/two bld/e.1/one.c},
|
||||||
%r{gcc -c -o build/e.1/src/two/two.c.o -MMD -MF build/e.1/src/two/two.c.o.mf -Isrc -Isrc/one -Isrc/two src/two/two.c},
|
%r{gcc -c -o bld/e.1/bld/two.c.o -MMD -MF bld/e.1/bld/two.c.o.mf -Isrc -Isrc/one -Isrc/two bld/two.c},
|
||||||
%r{gcc -o program.exe build/e.1/src/two/two.c.o build/e.1/one.o},
|
%r{gcc -o bld/program.exe bld/e.1/one.o bld/e.1/bld/two.c.o},
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1076,6 +1093,23 @@ EOF
|
|||||||
expect(result.status).to eq 0
|
expect(result.status).to eq 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "stores build artifacts in a directory according to Environment name" do
|
||||||
|
test_dir "typical"
|
||||||
|
|
||||||
|
result = run_rscons
|
||||||
|
expect(File.exist?("build/typical/typical.exe")).to be_truthy
|
||||||
|
expect(File.exist?("build/typical/src/one/one.c.o")).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
it "names Environment during clone" do
|
||||||
|
test_dir "typical"
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "clone_and_name.rb")
|
||||||
|
expect(File.exist?("build/typical/typical.exe")).to be_truthy
|
||||||
|
expect(File.exist?("build/typical/src/one/one.c.o")).to be_truthy
|
||||||
|
expect(Dir.exist?("build/e.1")).to be_falsey
|
||||||
|
end
|
||||||
|
|
||||||
context "colored output" do
|
context "colored output" do
|
||||||
it "does not output in color with --color=off" do
|
it "does not output in color with --color=off" do
|
||||||
test_dir("simple")
|
test_dir("simple")
|
||||||
@ -1296,7 +1330,8 @@ EOF
|
|||||||
context "Cache management" do
|
context "Cache management" do
|
||||||
it "prints a warning when the cache is corrupt" do
|
it "prints a warning when the cache is corrupt" do
|
||||||
test_dir("simple")
|
test_dir("simple")
|
||||||
File.open(Rscons::Cache::CACHE_FILE, "w") do |fh|
|
FileUtils.mkdir("build")
|
||||||
|
File.open("build/.rsconscache", "w") do |fh|
|
||||||
fh.puts("[1]")
|
fh.puts("[1]")
|
||||||
end
|
end
|
||||||
result = run_rscons
|
result = run_rscons
|
||||||
@ -1645,6 +1680,21 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "Size builder" do
|
||||||
|
it "generates a size file" do
|
||||||
|
test_dir "simple"
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "size.rb")
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
/Linking .*simple\.exe/,
|
||||||
|
/Size .*simple\.exe .*simple\.size/,
|
||||||
|
])
|
||||||
|
expect(File.exist?("simple.exe")).to be_truthy
|
||||||
|
expect(File.exist?("simple.size")).to be_truthy
|
||||||
|
expect(File.read("simple.size")).to match /text.*data.*bss/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "multi-threading" do
|
context "multi-threading" do
|
||||||
it "waits for subcommands in threads for builders that support threaded commands" do
|
it "waits for subcommands in threads for builders that support threaded commands" do
|
||||||
test_dir("simple")
|
test_dir("simple")
|
||||||
@ -1748,6 +1798,22 @@ EOF
|
|||||||
expect(result.status).to_not eq 0
|
expect(result.status).to_not eq 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "automatically runs the configure operation if the project is not yet configured in the given build directory" do
|
||||||
|
test_dir "configure"
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "check_c_compiler.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
expect(result.stdout).to match /Checking for C compiler\.\.\./
|
||||||
|
expect(Dir.exist?("build/_configure")).to be_truthy
|
||||||
|
|
||||||
|
result = run_rscons(rsconscript: "check_c_compiler.rb", rscons_args: %w[--build=bb])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
expect(result.stdout).to match /Checking for C compiler\.\.\./
|
||||||
|
expect(Dir.exist?("bb/_configure")).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
context "check_c_compiler" do
|
context "check_c_compiler" do
|
||||||
{"check_c_compiler.rb" => "when no arguments are given",
|
{"check_c_compiler.rb" => "when no arguments are given",
|
||||||
"check_c_compiler_find_first.rb" => "when arguments are given"}.each_pair do |rsconscript, desc|
|
"check_c_compiler_find_first.rb" => "when arguments are given"}.each_pair do |rsconscript, desc|
|
||||||
@ -2284,7 +2350,6 @@ EOF
|
|||||||
expect(result.stderr).to eq ""
|
expect(result.stderr).to eq ""
|
||||||
expect(result.status).to eq 0
|
expect(result.status).to eq 0
|
||||||
expect(result.stdout).to match /Configuring configure test\.\.\./
|
expect(result.stdout).to match /Configuring configure test\.\.\./
|
||||||
expect(result.stdout).to match /Setting build directory\.\.\. bb/
|
|
||||||
expect(result.stdout).to match %r{Setting prefix\.\.\. /my/prefix}
|
expect(result.stdout).to match %r{Setting prefix\.\.\. /my/prefix}
|
||||||
expect(result.stdout).to match /Checking for C compiler\.\.\. gcc/
|
expect(result.stdout).to match /Checking for C compiler\.\.\. gcc/
|
||||||
expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. g\+\+/
|
expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. g\+\+/
|
||||||
@ -2295,6 +2360,8 @@ EOF
|
|||||||
expect(result.stdout).to match /Checking for D import 'std.stdio'\.\.\. found/
|
expect(result.stdout).to match /Checking for D import 'std.stdio'\.\.\. found/
|
||||||
expect(result.stdout).to match /Checking for library 'm'\.\.\. found/
|
expect(result.stdout).to match /Checking for library 'm'\.\.\. found/
|
||||||
expect(result.stdout).to match /Checking for program 'ls'\.\.\. .*ls/
|
expect(result.stdout).to match /Checking for program 'ls'\.\.\. .*ls/
|
||||||
|
expect(Dir.exist?("build")).to be_falsey
|
||||||
|
expect(Dir.exist?("bb/_configure")).to be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it "aggregates multiple set_define's" do
|
it "aggregates multiple set_define's" do
|
||||||
@ -2357,7 +2424,6 @@ EOF
|
|||||||
expect(result.status).to eq 0
|
expect(result.status).to eq 0
|
||||||
expect(File.exists?("simple.o")).to be_falsey
|
expect(File.exists?("simple.o")).to be_falsey
|
||||||
expect(File.exists?("build")).to be_falsey
|
expect(File.exists?("build")).to be_falsey
|
||||||
expect(File.exists?(Rscons::Cache::CACHE_FILE)).to be_falsey
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -2742,6 +2808,71 @@ EOF
|
|||||||
expect(result.status).to_not eq 0
|
expect(result.status).to_not eq 0
|
||||||
expect(result.stdout).to_not match /top configure/
|
expect(result.stdout).to_not match /top configure/
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "does not pass RSCONS_BUILD_DIR to subsidiary scripts" do
|
||||||
|
test_dir "subsidiary"
|
||||||
|
passenv["RSCONS_BUILD_DIR"] = "buildit"
|
||||||
|
result = run_rscons(op: %W[configure])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(Dir.exist?("build")).to be_falsey
|
||||||
|
expect(Dir.exist?("buildit")).to be_truthy
|
||||||
|
expect(Dir.exist?("sub/build")).to be_truthy
|
||||||
|
expect(Dir.exist?("sub/buildit")).to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "sh method" do
|
||||||
|
it "executes the command given" do
|
||||||
|
test_dir "sh"
|
||||||
|
result = run_rscons(rsconscript: "sh.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
"hi there",
|
||||||
|
"1 2",
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints the command when executing verbosely" do
|
||||||
|
test_dir "sh"
|
||||||
|
result = run_rscons(rsconscript: "sh.rb", rscons_args: %w[-v])
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
verify_lines(lines(result.stdout), [
|
||||||
|
%r{echo 'hi there'},
|
||||||
|
"hi there",
|
||||||
|
%r{echo 1 2},
|
||||||
|
"1 2",
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "terminates execution on failure" do
|
||||||
|
test_dir "sh"
|
||||||
|
result = run_rscons(rsconscript: "sh_fail.rb")
|
||||||
|
expect(result.stderr).to match /sh_fail\.rb:2:.*foobar42/
|
||||||
|
expect(result.status).to_not eq 0
|
||||||
|
expect(result.stdout).to_not match /continued/
|
||||||
|
end
|
||||||
|
|
||||||
|
it "continues execution on failure when :continue option is set" do
|
||||||
|
test_dir "sh"
|
||||||
|
result = run_rscons(rsconscript: "sh_fail_continue.rb")
|
||||||
|
expect(result.stderr).to match /sh_fail_continue\.rb:2:.*foobar42/
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
expect(result.stdout).to match /continued/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "FileUtils methods" do
|
||||||
|
it "defines FileUtils methods to be available in the build script" do
|
||||||
|
test_dir "typical"
|
||||||
|
result = run_rscons(rsconscript: "fileutils_methods.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
expect(Dir.exist?("foobar")).to be_truthy
|
||||||
|
expect(Dir.exist?("foo")).to be_falsey
|
||||||
|
expect(File.exist?("foobar/baz/b.txt")).to be_truthy
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user