Support naming environments - close #140

This commit is contained in:
Josh Holtrop 2022-01-13 12:56:23 -05:00
parent 97dbaeb82d
commit a316c4f922
6 changed files with 65 additions and 9 deletions

View 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

View 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

View File

@ -82,6 +82,15 @@ files, dependency files, etc...) and build system metadata in a
"build directory". "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 default a build directory named "build" is used, but this can be overridden
by the user by using the `-b`/`--build` command-line option. by the user by using the `-b`/`--build` command-line option.
@ -495,21 +504,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
@ -517,6 +531,8 @@ 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.

View File

@ -16,7 +16,7 @@ module Rscons
def initialize(options) def initialize(options)
# Default options. # Default options.
options[:prefix] ||= "/usr/local" options[:prefix] ||= "/usr/local"
@work_dir = "#{Rscons.application.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

View File

@ -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 = "#{Rscons.application.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)

View File

@ -1085,6 +1085,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")
@ -1765,13 +1782,13 @@ 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 /Checking for C compiler\.\.\./ expect(result.stdout).to match /Checking for C compiler\.\.\./
expect(Dir.exist?("build/configure")).to be_truthy expect(Dir.exist?("build/_configure")).to be_truthy
result = run_rscons(rsconscript: "check_c_compiler.rb", rscons_args: %w[--build=bb]) result = run_rscons(rsconscript: "check_c_compiler.rb", rscons_args: %w[--build=bb])
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 /Checking for C compiler\.\.\./ expect(result.stdout).to match /Checking for C compiler\.\.\./
expect(Dir.exist?("bb/configure")).to be_truthy expect(Dir.exist?("bb/_configure")).to be_truthy
end end
context "check_c_compiler" do context "check_c_compiler" do
@ -2321,7 +2338,7 @@ EOF
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?("build")).to be_falsey
expect(Dir.exist?("bb/configure")).to be_truthy expect(Dir.exist?("bb/_configure")).to be_truthy
end end
it "aggregates multiple set_define's" do it "aggregates multiple set_define's" do