Add variants - #137

Add build script methods: variant, variant_group, with_variants
This commit is contained in:
Josh Holtrop 2022-02-16 12:23:30 -05:00
parent 5b6353395d
commit 19dee2b2a5
11 changed files with 223 additions and 2 deletions

View File

@ -0,0 +1,13 @@
variant "debug"
variant "release"
with_variants do
env "prog" do |env|
if variant("debug")
env["CPPDEFINES"] << "DEBUG"
else
env["CPPDEFINES"] << "NDEBUG"
end
env.Program("^/prog.exe", "prog.c")
end
end

View File

@ -0,0 +1,5 @@
variant "foo"
with_variants do
with_variants do
end
end

View File

@ -0,0 +1,5 @@
variant_group
variant_group
variant "foo"
with_variants do
end

View File

@ -0,0 +1,2 @@
with_variants do
end

View File

@ -0,0 +1,27 @@
variant_group "desktop-environment" do
variant "kde"
variant "gnome"
end
variant_group "debug" do
variant "debug"
variant "release"
end
with_variants do
env "prog" do |env|
if variant("kde")
env["CPPDEFINES"] << "KDE"
end
if variant("gnome")
env["CPPDEFINES"] << "GNOME"
end
if variant("debug")
env["CPPDEFINES"] << "DEBUG"
end
if variant("release")
env["CPPDEFINES"] << "NDEBUG"
end
env.Program("^/prog.exe", "prog.c")
end
end

View File

@ -0,0 +1,13 @@
variant "debug"
variant "release", key: nil
with_variants do
env "prog" do |env|
if variant("debug")
env["CPPDEFINES"] << "DEBUG"
else
env["CPPDEFINES"] << "NDEBUG"
end
env.Program("^/prog.exe", "prog.c")
end
end

View File

@ -0,0 +1,4 @@
int main(int argc, char * argv[])
{
return 42;
}

View File

@ -5,6 +5,10 @@ module Rscons
# Functionality for an instance of the rscons application invocation.
class Application
# @return [Array<String>]
# Active variant names.
attr_reader :active_variants
# @return [String]
# Top-level build directory.
attr_accessor :build_dir
@ -35,6 +39,7 @@ module Rscons
@build_dir = ENV["RSCONS_BUILD_DIR"] || "build"
ENV.delete("RSCONS_BUILD_DIR")
@n_threads = Util.determine_n_threads
@variant_groups = []
end
# Run the application.
@ -194,6 +199,64 @@ module Rscons
cache.write
end
# Define a variant, or within a with_variants block, query if it is
# active.
#
# @param name [String]
# Variant name.
def variant(name, options = {})
if @active_variants
!!@active_variants.find {|variant| variant[:name] == name}
else
if @variant_groups.empty?
variant_group
end
options = options.dup
options[:name] = name
options[:active] = options.fetch(:default, true)
options[:key] = options.fetch(:key, name)
@variant_groups.last[:variants] << options
end
end
# Create a variant group.
def variant_group(*args, &block)
if args.first.is_a?(String)
name = args.slice!(0)
end
@variant_groups << {name: name, variants: []}
if block
block[]
end
end
# Iterate through variants.
def with_variants(&block)
if @active_variants
raise "with_variants cannot be called within another with_variants block"
end
if @variant_groups.empty?
raise "with_variants cannot be called with no variants defined"
end
if @variant_groups.any? {|variant_group| variant_group[:variants].empty?}
raise "Error: empty variant group found"
end
iter_vgs = lambda do |variants|
if variants.size == @variant_groups.size
@active_variants = variants
block[]
@active_variants = nil
else
@variant_groups[variants.size][:variants].each do |variant|
if variant[:active]
iter_vgs[variants + [variant]]
end
end
end
end
iter_vgs[[]]
end
private
def show_script_tasks

View File

@ -93,10 +93,14 @@ module Rscons
def initialize(*args, &block)
@id = self.class.get_id
if args.first.is_a?(String)
@name = args.slice!(0)
base_name = args.slice!(0)
else
@name = "e.#{@id}"
base_name = "e.#{@id}"
end
variant_keys = (Rscons.application.active_variants || []).map do |variant|
variant[:key]
end.compact
@name = [base_name, *variant_keys].join("-")
options = args.first || {}
Rscons.application.check_configure
unless Cache.instance["configuration_data"]["configured"]

View File

@ -244,6 +244,22 @@ module Rscons
Util.task(*args, &block)
end
# Define a variant, or within a with_variants block, query if it is
# active.
def variant(*args)
Rscons.application.variant(*args)
end
# Create a variant group.
def variant_group(*args, &block)
Rscons.application.variant_group(*args, &block)
end
# Iterate through variants.
def with_variants(&block)
Rscons.application.with_variants(&block)
end
[
:cd,
:chmod,

View File

@ -3039,4 +3039,73 @@ EOF
end
end
context "variants" do
it "appends variant names to environment names to form build directories" do
test_dir "variants"
result = run_rscons
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(File.exist?("build/prog-debug/prog.exe")).to be_truthy
expect(File.exist?("build/prog-release/prog.exe")).to be_truthy
end
it "allows querying active variants and changing behavior" do
test_dir "variants"
result = run_rscons(args: %w[-v])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(File.exist?("build/prog-debug/prog.exe")).to be_truthy
expect(File.exist?("build/prog-release/prog.exe")).to be_truthy
expect(result.stdout).to match %r{gcc .*-o.*build/prog-debug/.*-DDEBUG}
expect(result.stdout).to match %r{gcc .*-o.*build/prog-release/.*-DNDEBUG}
end
it "allows specifying a nil key for a variant" do
test_dir "variants"
result = run_rscons(args: %w[-v -f nil_key.rb])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(File.exist?("build/prog-debug/prog.exe")).to be_truthy
expect(File.exist?("build/prog/prog.exe")).to be_truthy
expect(result.stdout).to match %r{gcc .*-o.*build/prog-debug/.*-DDEBUG}
expect(result.stdout).to match %r{gcc .*-o.*build/prog/.*-DNDEBUG}
end
it "allows multiple variant groups" do
test_dir "variants"
result = run_rscons(args: %w[-v -f multiple_groups.rb])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(File.exist?("build/prog-kde-debug/prog.exe")).to be_truthy
expect(File.exist?("build/prog-kde-release/prog.exe")).to be_truthy
expect(File.exist?("build/prog-gnome-debug/prog.exe")).to be_truthy
expect(File.exist?("build/prog-gnome-release/prog.exe")).to be_truthy
expect(result.stdout).to match %r{gcc .*-o.*build/prog-kde-debug/.*-DKDE.*-DDEBUG}
expect(result.stdout).to match %r{gcc .*-o.*build/prog-kde-release/.*-DKDE.*-DNDEBUG}
expect(result.stdout).to match %r{gcc .*-o.*build/prog-gnome-debug/.*-DGNOME.*-DDEBUG}
expect(result.stdout).to match %r{gcc .*-o.*build/prog-gnome-release/.*-DGNOME.*-DNDEBUG}
end
it "raises an error when with_variants is called within another with_variants block" do
test_dir "variants"
result = run_rscons(args: %w[-f error_nested_with_variants.rb])
expect(result.stderr).to match %r{with_variants cannot be called within another with_variants block}
expect(result.status).to_not eq 0
end
it "raises an error when with_variants is called with no variants defined" do
test_dir "variants"
result = run_rscons(args: %w[-f error_with_variants_without_variants.rb])
expect(result.stderr).to match %r{with_variants cannot be called with no variants defined}
expect(result.status).to_not eq 0
end
it "raises an error when with_variants is called with an empty variant group" do
test_dir "variants"
result = run_rscons(args: %w[-f error_with_variants_with_empty_variant_group.rb])
expect(result.stderr).to match %r{Error: empty variant group found}
expect(result.status).to_not eq 0
end
end
end