Update user guide for v3.0.0

Document variants
This commit is contained in:
Josh Holtrop 2022-02-27 15:51:20 -05:00
parent b82d6f2e62
commit 88a8f2395d

View File

@ -12,6 +12,7 @@ It supports the following features:
* colorized output with build progress
* build hooks
* user-defined tasks with dependencies and custom parameters
* build variants
At its core, Rscons is mainly an engine to:
@ -67,8 +68,8 @@ incorrect decision being made to not rebuild when a rebuild is necessary.
### Build Flexibility
Rscons supports multiple configurations of compilation flags or build options
across multiple environments to build output files in different ways according
to the user's desire.
across multiple environments or build variants to build output files in
different ways according to the user's desire.
For example, the same source files can be built into a release executable, but
also compiled with different compilation flags or build options into a test
executable.
@ -143,15 +144,18 @@ different version control systems):
Rscons is typically invoked from the command-line as `./rscons`.
./rscons [global options] [[task] [task options] ...]
Usage: ./rscons [global options] [[task] [task options] ...]
Global options:
-A, --all Show all tasks (even without descriptions) in task list
-b BUILD, --build=BUILD Set build directory (default: build)
-e VS, --variants=VS Enable or disable variants
-f FILE Use FILE as Rsconscript
-F, --show-failure Show failed command log from previous build and exit
-h, --help Show rscons help and exit
-j N, --nthreads=N Set number of threads
-r COLOR, --color=COLOR Set color mode (off, auto, force)
-T, --tasks Show task list and parameters and exit
-v, --verbose Run verbosely
--version Show rscons version and exit
@ -181,6 +185,19 @@ Rscons execution.
The user can also invoke Rscons with the `-v` global command-line option which
will cause Rscons to print each command it is executing.
## Rscons Operation Phases
When Rscons executes, it performs the following phases:
- Parse the command line.
- Exit if --help or --version specified.
- Load the build script.
- Show tasks and exit if -T specified.
- Configure the project by running the `configure` task if necessary (the
project has not yet been configured, autoconf is set to true, and the user
is requesting to execute a task that is marked with autoconf set to true)
- Execute user-requested tasks.
#> The Build Script
Rscons looks for instructions for what to build by reading a build script file
@ -188,10 +205,8 @@ called `Rsconscript` (or `Rsconscript.rb`).
Here is a simple example `Rsconscript` file:
```ruby
default do
Environment.new do |env|
env do |env|
env.Program("myprog.exe", glob("src/**/*.c"))
end
end
```
@ -203,7 +218,7 @@ The `Rsconscript` file is a Ruby script.
##> Tasks
Tasks are the high-level user interface for performing functionality in a build
Tasks are a high-level user interface for performing functionality in a build
script.
Tasks can create Environments that perform compilation/linking steps.
Tasks can also execute arbitrary commands or perform any miscellaneous logic.
@ -219,7 +234,7 @@ Example:
```ruby
task "build" do
Environment.new do |env|
env do |env|
env.Program("^^/proj.elf", glob("src/**/*.c"))
end
end
@ -240,9 +255,13 @@ Any newly specified dependencies are added to the current dependencies.
Any action block is appended to the task's list of action blocks to execute
when the task is executed.
Note that for a simple project, the build script may not need to define any
tasks at all and could just make use of the Rscons built-in default task (see
${#Default Task}).
###> Task Parameters
Tasks can also take parameters.
Tasks can accept parameters.
Parameters are defined by the build script author, and have default values.
The user can override parameter values on the command line.
@ -261,7 +280,7 @@ task "build", params: [
param("myparam", "defaultvalue", true, "My special parameter"),
param("xyz", nil, false, "Enable the xyz feature"),
] do |task, params|
Environment.new do |env|
env do |env|
env["CPPDEFINES"] << "SOMEMACRO=#{params["myparam"]}"
if params["flag"]
env["CPPDEFINES"] << "ENABLE_FEATURE_XYZ"
@ -399,8 +418,6 @@ configuration functionality that Rscons provides.
The `default` task is special in that Rscons will execute it if no other task
has been requested by the user on the command line.
It is entirely feasible for the default task to be the only task defined for a
project, and simple projects may wish to do just that.
The default task can also be used to declare a dependency on another task that
would effectively become the default.
@ -432,7 +449,8 @@ It will not remove the cached configuration options.
The `distclean` task is built-in to Rscons.
It removes all built target files and all cached configuration options.
Generally it will get the project directory back to the state it was in when
unpacked before any configuration or build operations took place.
unpacked or checked out, before any configuration or build operations took
place.
It will not remove items installed by an Install builder.
####> Install Task
@ -734,17 +752,16 @@ If set, a build define of the specified String will be added to the
##> Building Targets
Building target files is accomplished by using Environments.
Environments are typically created within the default task or any user-defined
tasks.
Environments can be created at the top level of the build script, or from
within a task action block.
Here is an example `default` task block demonstrating how to create an
Environment and register a build target:
Environments are created with the `env` build script method.
Here is an example build script that creates an Environment and registers a
Program build target:
```ruby
default do
Environment.new do |env|
env do |env|
env.Program("myprog.exe", glob("src/**/*.c"))
end
end
```
@ -759,24 +776,21 @@ An Environment includes:
- a collection of construction variables
- a collection of build hooks
- a collection of user-registered build targets
- a build root
- a build root directory
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
Rscons build directory.
It is based on the Environment name.
The Environment's build root is a directory with the same name as the
Environment, created within the top-level Rscons build directory.
By default it holds all intermediate files generated by Rscons that are needed
to produce a user-specified build target.
For example, for the `Rsconscript`:
```ruby
default do
Environment.new(name: "myproj") do |env|
env "myproj" do |env|
env.Program("myprog.exe", glob("src/**/*.c"))
end
end
```
@ -786,6 +800,9 @@ 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
files.
Source and target paths passed to a Builder (e.g. Program) can begin with "^/"
to indicate that Rscons should expand those paths to be relative to the
Environment's build root.
###> Construction Variables
@ -797,11 +814,9 @@ construction variables.
Example:
```ruby
default do
Environment.new do |env|
env do |env|
env["CCFLAGS"] += %w[-O2 -Wall]
env["LIBS"] += %w[m]
end
end
```
@ -813,6 +828,7 @@ It also instructs the linker to link against the `m` library.
* uppercase strings - the default construction variables that Rscons uses
* strings beginning with "_" - set and used internally by builders
* strings with a ":" as "#{task_name}:#{parameter_name}" - set to task parameter values
* symbols, lowercase strings - reserved as user-defined construction variables
###> Builders
@ -1099,7 +1115,7 @@ and flags can be specified with `SIZEFLAGS`.
###> Phony Targets
rscons supports phony build targets.
Rscons supports phony build targets.
Normally, a builder produces an output file, and executes whenever the input
files or command have changed.
A phony build target can be used to register a builder that does not produce
@ -1142,8 +1158,7 @@ build target or source file names.
Example:
```ruby
default do
Environment.new do |env|
env do |env|
env["CFLAGS"] << "-Wall"
env.add_build_hook do |builder|
# Compile sources from under src/tests without the -Wall flag.
@ -1152,7 +1167,6 @@ default do
end
end
env.Program("program.exe", glob("src/**/*.c"))
end
end
```
@ -1166,7 +1180,7 @@ Build hooks and post-build hooks can register new build targets.
###> Barriers
Normally Rscons will parallelize all builders.
Normally Rscons will parallelize all builders executed within an Environment.
A barrier can be used to separate sets of build targets.
All build targets registered before the barrier is created will be built before
Rscons will schedule any build targets after the barrier.
@ -1176,11 +1190,113 @@ In other words, build targets are not parallelized across a barrier.
env.barrier
```
##> Variants
Rscons supports build variants.
Variants can be used to built multiple variations of the same item with a
specific change.
For example, a desktop application with the same sources could be built to
target KDE or GNOME using build variants.
It is up to the build script author to define the variants and what effect they
have on the build.
This build script defines "kde" and "gnome" variants:
```ruby
variant "kde"
variant "gnome"
with_variants do
env "prog" do |env|
if variant "kde"
env["CPPDEFINES"] << "KDE"
end
if variant "gnome"
env["CPPDEFINES"] << "GNOME"
end
env.Program("^/prog.exe", "src/**/*.cpp")
end
end
```
The `variant` build script method has two uses:
* At the top of the build script, it defines a variant.
* Within a `with_variants` block, it queries for whether the given variant is
active.
The `with_variants` build script method allows the power of variants to be
harnessed.
It iterates through each enabled variant and calls the given block.
In this example, the block would be called twice, once with the "kde" variant
active, and the second time with the "gnome" variant active.
Each `env()` call creates an Environment, so two environments are created.
When an Environment is created within a `with_variants` block, the
Environment's name has the active variant(s) appended to the given Environment
name (if any), and separated by a "-".
In this example, a "prog-kde" Environment would be created with build root
build/prog-kde and -DKDE would be passed to the compiler when compiling each
source.
Next a "prog-gnome" Environment would be created with build root
build/prog-gnome and -DGNOME would be passed to the compiler when compiling
the sources.
Variants are enabled by default, but can be disabled by passing a `false` value
to the `:default` option of the `variant` method.
For example:
```ruby
${include build_tests/variants/default.rb}
```
The `rscons` command line interface provides a `-e`/`--variants` argument which
allows the user to enable a different set of variants from those enabled by
default according to the build script author.
This argument accepts a comma-separated list of variants to enable.
Each entry in the list can begin with "-" to disable the variant instead of
enable it.
If the list begins with "+" or "-", then the entire given list modifies the
defaults given in the build script.
Otherwise, it exactly specifies which variants should be enabled, and any
variant not listed is disabled.
When the project is configured, the set of enabled variants is recorded and
remembered for later Rscons invocations.
This way, a user working on a single variant of a project does not need to
specify the `-e`/`--variants` option on each build operation.
The `variant_enabled?` build script method can be called to query whether the
given variant is enabled.
###> Variant Groups
Variants may be grouped, which allows the build script author to define
multiple combinations of desired variations to build with.
For example:
```ruby
${include build_tests/variants/multiple_groups.rb}
```
This build script executes the block given to `with_variants` four times and
results in four Environments being created:
* prog-kde-debug
* prog-kde-release
* prog-gnome-debug
* prog-gnome-release
The command `./rscons -e-debug` would build just "prog-kde-release" and "prog-gnome-release".
The command `./rscons --variants kde,release` would build just "prog-kde-release".
##> Build Script Methods
`rscons` provides several methods that a build script can use.
* `autoconf` (see ${#Configure Task})
* `build_dir` which returns the path to the top-level Rscons build directory
* `clean` (see ${#Clean Task})
* `configure` (see ${#Configure Task})
* `default` (see ${#Default Task})
@ -1197,6 +1313,10 @@ env.barrier
* `sh` (see (${#Executing Commands: The sh Method})
* `task` (see ${#Tasks})
* `uninstall` (see ${#Uninstall Task})
* `variant` (see ${#Variants})
* `variant_enabled?` (see ${#Variant Groups})
* `variant_group` (see ${#Variant Groups})
* `with_variants` (see ${#Variant Groups})
Additionally, the following methods from the Ruby
[FileUtils](https://ruby-doc.org/stdlib-3.1.0/libdoc/fileutils/rdoc/FileUtils.html)
@ -1237,10 +1357,8 @@ rather than file system directory ordering).
Example use:
```ruby
default do
Environment.new do |env|
env do |env|
env.Program("mytests", glob("src/**/*.cc", "test/**/*.cc"))
end
end
```
@ -1406,7 +1524,7 @@ class Rscons::Builders::Mine < Rscons::Builder
end
default do
Environment.new do |env|
env do |env|
env.add_builder(Rscons::Builders::Mine)
end
end
@ -1429,7 +1547,7 @@ Rscons::DEFAULT_BUILDERS << :Special
load "SpecialBuilder.rb"
default do
Environment.new do |env|
env do |env|
# A build target using the "Special" builder can be registered.
env.Special("target", "source")
end
@ -1656,40 +1774,36 @@ ${include lib/rscons/default_construction_variables.rb}
### Example: Building a C Program
```ruby
default do
Environment.new do |env|
env do |env|
env["CFLAGS"] << "-Wall"
env.Program("program", glob("src/**/*.c"))
end
end
```
### Example: Building a D Program
```ruby
default do
Environment.new do |env|
env do |env|
env["DFLAGS"] << "-Wall"
env.Program("program", glob("src/**/*.d"))
end
end
```
### Example: Cloning an Environment
```ruby
default do
main_env = Environment.new do |env|
env["CFLAGS"] = ["-DSOME_DEFINE", "-O3"]
main_env = env do |env|
env["CFLAGS"] = ["-fshort-enums", "-O3"]
env["CPPDEFINES"] << "SOME_DEFINE"
env["LIBS"] = ["SDL"]
env.Program("program", glob("src/**/*.cc"))
end
end
debug_env = main_env.clone do |env|
test_env = main_env.clone do |env|
env["CFLAGS"] -= ["-O3"]
env["CFLAGS"] += ["-g", "-O0"]
env.Program("program-debug", glob("src/**/*.cc"))
end
env["CPPDEFINES"] = "ENABLE_TESTS"
env.Program("program-test", glob("src/**/*.cc"))
end
```
@ -1709,20 +1823,17 @@ EOF
end
end
default do
Environment.new do |env|
env do |env|
env.add_builder(GenerateFoo)
env.GenerateFoo("foo.h", [])
env.Program("a.out", glob("*.c"))
end
end
```
### Example: Using different compilation flags for some sources
```ruby
default do
Environment.new do |env|
env do |env|
env["CFLAGS"] = ["-O3", "-Wall"]
env.add_build_hook do |builder|
if builder.sources.first =~ %r{src/third-party/}
@ -1730,27 +1841,22 @@ default do
end
end
env.Program("program", glob("**/*.cc"))
end
end
```
### Example: Creating a static library
```ruby
default do
Environment.new do |env|
env do |env|
env.Library("mylib.a", glob("src/**/*.c"))
end
end
```
### Example: Creating a C++ parser source from a Yacc/Bison input file
```ruby
default do
Environment.new do |env|
env do |env|
env.CFile("^/parser.tab.cc", "parser.yy")
end
end
```