Compare commits

...

23 Commits
wip ... master

Author SHA1 Message Date
8f0f320a07 v3.0.2 2022-03-14 00:36:17 -04:00
12f6936084 Update CHANGELOG for v3.0.2 2022-03-14 00:36:05 -04:00
866b40d872 Configure parameters should not be stored as unscoped construction variables - close #160 2022-03-14 00:34:52 -04:00
f06d37c8b9 Compiler check configure methods should respect :use flag - close #159 2022-03-14 00:27:02 -04:00
21f8e2435e v3.0.1 2022-03-13 22:27:16 -04:00
97c4f7c757 Update CHANGELOG for v3.0.1 2022-03-13 22:27:16 -04:00
b3df37e9ea Do not configure for clean tasks when not yet configured - close #158 2022-03-13 22:27:16 -04:00
1bf1c30242 Load configure task arguments before early configure operations - close #157 2022-03-13 20:16:01 -04:00
b932380b3b Avoid running configure operation twice - close #156 2022-03-11 21:17:07 -05:00
e3ea429253 Fix running dspec task with argument 2022-03-11 21:13:52 -05:00
dca4c49770 Avoid trailing spaces in distributable script 2022-03-07 21:08:17 -05:00
b068fe7574 Test that custom clean task action blocks are execution 2022-02-28 11:59:52 -05:00
ecd91e1171 v3.0.0 2022-02-27 20:55:16 -05:00
f36b71af3f Fix ARCMD spec for Linux and MacOS 2022-02-27 19:16:59 -05:00
90c3867cae Tweak specs to all pass cleanly on MacOS 2022-02-27 19:10:18 -05:00
20b5020284 bundle update 2022-02-27 18:06:39 -05:00
cb540741a4 Clarify task parameter construction variable names 2022-02-27 17:44:01 -05:00
bc17a9b38f Test that clean task does not process environments 2022-02-27 17:34:48 -05:00
cec1331054 Rename build specs from operation to task 2022-02-27 17:34:38 -05:00
bb4657e465 Process environments created during task execution phase 2022-02-27 16:55:59 -05:00
29ca9b3f13 Fix YARD warnings 2022-02-27 16:40:09 -05:00
5ab982b84c Add GCC Cross Compiler example build script 2022-02-27 16:28:09 -05:00
e6e860e3c1 Document download build script method 2022-02-27 16:27:24 -05:00
27 changed files with 472 additions and 95 deletions

View File

@ -1,3 +1,18 @@
## v3.0.2
### Fixes
- #159 - Compiler check configure methods should respect :use flag
- #160 - Configure parameters should not be stored as unscoped construction variables
## v3.0.1
### Fixes
- #156 - Avoid running configure operation twice
- #157 - Load configure task arguments before early configure operations
- #158 - Do not configure for clean tasks when not yet configured
## v3.0.0 ## v3.0.0
- #136 - Move rsconscache into build directory - #136 - Move rsconscache into build directory

View File

@ -1,32 +1,38 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
diff-lcs (1.4.4) diff-lcs (1.5.0)
docile (1.1.5) docile (1.1.5)
json (2.5.1) json (2.6.1)
psych (4.0.3)
stringio
rake (13.0.6) rake (13.0.6)
rdoc (6.3.2) rdoc (6.4.0)
psych (>= 4.0.0)
redcarpet (3.5.1) redcarpet (3.5.1)
rspec (3.10.0) rspec (3.11.0)
rspec-core (~> 3.10.0) rspec-core (~> 3.11.0)
rspec-expectations (~> 3.10.0) rspec-expectations (~> 3.11.0)
rspec-mocks (~> 3.10.0) rspec-mocks (~> 3.11.0)
rspec-core (3.10.1) rspec-core (3.11.0)
rspec-support (~> 3.10.0) rspec-support (~> 3.11.0)
rspec-expectations (3.10.1) rspec-expectations (3.11.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0) rspec-support (~> 3.11.0)
rspec-mocks (3.10.2) rspec-mocks (3.11.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0) rspec-support (~> 3.11.0)
rspec-support (3.10.2) rspec-support (3.11.0)
simplecov (0.15.1) simplecov (0.15.1)
docile (~> 1.1.0) docile (~> 1.1.0)
json (>= 1.8, < 3) json (>= 1.8, < 3)
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.2) simplecov-html (0.10.2)
stringio (3.0.1)
syntax (1.2.2) syntax (1.2.2)
yard (0.9.26) webrick (1.7.0)
yard (0.9.27)
webrick (~> 1.7.0)
PLATFORMS PLATFORMS
ruby ruby
@ -43,4 +49,4 @@ DEPENDENCIES
yard yard
BUNDLED WITH BUNDLED WITH
2.1.4 2.2.31

View File

@ -35,7 +35,7 @@ task :dspec, [:example_string] => :build_dist do |task, args|
FileUtils.mkdir_p("test") FileUtils.mkdir_p("test")
FileUtils.cp("dist/rscons", "test/rscons.rb") FileUtils.cp("dist/rscons", "test/rscons.rb")
ENV["dist_specs"] = "1" ENV["dist_specs"] = "1"
Rake::Task["spec"].execute(args.example_string) Rake::Task["spec"].execute(args)
ENV.delete("dist_specs") ENV.delete("dist_specs")
FileUtils.rm_f(Dir.glob(".rscons-*")) FileUtils.rm_f(Dir.glob(".rscons-*"))
end end

View File

@ -0,0 +1,12 @@
configure do
check_c_compiler "clang", use: "clang"
check_c_compiler
end
env "t1" do |env|
env.Program("test_gcc.exe", "simple.c")
end
env "t2", use: "clang" do |env|
env.Program("test_clang.exe", "simple.c")
end

View File

@ -0,0 +1,12 @@
configure do
check_cxx_compiler "clang++", use: "clang"
check_cxx_compiler
end
env "t1" do |env|
env.Program("test_gcc.exe", "simple.cc")
end
env "t2", use: "clang" do |env|
env.Program("test_clang.exe", "simple.cc")
end

View File

@ -0,0 +1,12 @@
configure do
check_d_compiler "ldc2", use: "ldc2"
check_d_compiler
end
env "t1" do |env|
env.Program("test_gcc.exe", "simple.d")
end
env "t2", use: "ldc2" do |env|
env.Program("test_ldc2.exe", "simple.d")
end

View File

@ -0,0 +1,6 @@
configure do
check_c_compiler
end
env do |env|
puts "Prefix is #{Task["configure"]["prefix"]}"
end

View File

@ -0,0 +1,6 @@
#include <iostream>
int main(int argc, char *argv[])
{
std::cout << "Hi" << std::endl;
}

View File

@ -0,0 +1,7 @@
import std.stdio;
int main()
{
writeln("Hello");
return 0;
}

View File

@ -1,4 +1,7 @@
env(echo: :command) do |env| env(echo: :command) do |env|
env.Program('library.exe', ['lib.a', 'three.c']) env["LIBS"] << "mylib"
env.Library("lib.a", ['one.c', 'two.c'], 'CPPFLAGS' => ['-Dmake_lib']) env["LIBPATH"] << "."
env.Program("library.exe", "one.c")
env.depends("library.exe", "libmylib.a")
env.Library("libmylib.a", ["two.c", "three.c"], "CPPFLAGS" => ["-Dmake_lib"])
end end

View File

@ -1,8 +1,11 @@
#include <stdio.h> #include <stdio.h>
#ifdef make_lib void two();
void three();
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
two();
printf("Library\n"); printf("Library\n");
three();
} }
#endif

View File

@ -1,4 +1,4 @@
env(echo: :command) do |env| env(echo: :command) do |env|
env["ARCMD"] = %w[ar rcf ${_TARGET} ${_SOURCES}] env["ARCMD"] = %w[ar rc ${_TARGET} ${_SOURCES}]
env.Library("lib.a", glob("*.c")) env.Library("lib.a", glob("*.c"))
end end

View File

@ -0,0 +1,3 @@
void three(void)
{
}

View File

@ -0,0 +1,3 @@
void two(void)
{
}

View File

@ -0,0 +1,7 @@
env do |env|
env.Program('simple.exe', Dir['*.c'])
end
clean do
puts "custom clean action"
end

View File

@ -0,0 +1,5 @@
default do
env do |env|
env.Program('simple.exe', Dir['*.c'])
end
end

View File

@ -1,5 +1,6 @@
env(echo: :command) do |env| env(echo: :command) do |env|
env["LD"] = "gcc" env["LD"] = "gcc"
mkdir_p("libdir")
env["LIBPATH"] += ["libdir"] env["LIBPATH"] += ["libdir"]
env.Program('simple.exe', Dir['*.c']) env.Program('simple.exe', Dir['*.c'])
end end

View File

@ -1,3 +1,6 @@
#ifdef ONE #ifdef ONE
#error ONE should not be defined #error ONE should not be defined
#endif #endif
void two(void)
{
}

View File

@ -446,6 +446,9 @@ end
See ${#Configuring the Project} for more details on how to make use of the See ${#Configuring the Project} for more details on how to make use of the
configuration functionality that Rscons provides. configuration functionality that Rscons provides.
Configure blocks must be defined in the Rsconscript file before any
environments are created.
####> Default Task ####> Default Task
The `default` task is special in that Rscons will execute it if no other task The `default` task is special in that Rscons will execute it if no other task
@ -787,7 +790,9 @@ Building target files is accomplished by using Environments.
Environments can be created at the top level of the build script, or from Environments can be created at the top level of the build script, or from
within a task action block. within a task action block.
Environments are created with the `env` build script method. Environments are created with the
[`env`](../yard/Rscons/Script/GlobalDsl.html#env-instance_method) build script
method.
Here is an example build script that creates an Environment and registers a Here is an example build script that creates an Environment and registers a
Program build target: Program build target:
@ -863,7 +868,7 @@ It also instructs the linker to link against the `m` library.
* uppercase strings - the default construction variables that Rscons uses * uppercase strings - the default construction variables that Rscons uses
* strings beginning with "_" - set and used internally by builders * strings beginning with "_" - set and used internally by builders
* strings with a ":" as "#{task_name}:#{parameter_name}" - set to task parameter values * lowercase strings with a ":" as "#{task_name}:#{parameter_name}" - set to task parameter values
* symbols, lowercase strings - reserved as user-defined construction variables * symbols, lowercase strings - reserved as user-defined construction variables
###> Builders ###> Builders
@ -1336,6 +1341,7 @@ The command `./rscons --variants kde,release` would build just "prog-kde-release
* `clean` (see ${#Clean Task}) * `clean` (see ${#Clean Task})
* `configure` (see ${#Configure Task}) * `configure` (see ${#Configure Task})
* `default` (see ${#Default Task}) * `default` (see ${#Default Task})
* `download` (see ${#Downloading Files: The download Method})
* `distclean` (see ${#Distclean Task}) * `distclean` (see ${#Distclean Task})
* `glob` (see ${#Finding Files: The glob Method}) * `glob` (see ${#Finding Files: The glob Method})
* `install` (see ${#Install Task}) * `install` (see ${#Install Task})
@ -1401,6 +1407,31 @@ end
This example would build the `mytests` executable from all `.cc` source files This example would build the `mytests` executable from all `.cc` source files
found recursively under the `src` or `test` directory. found recursively under the `src` or `test` directory.
###> Downloading Files: The download Method
The [`download`](../yard/Rscons/Script/GlobalDsl.html#download-instance_method)
method can be used to download a file from a given URL.
Example use:
```ruby
default do
download "https://ftp.gnu.org/gnu/gcc/gcc-#{gcc_version}/gcc-#{gcc_version}.tar.xz",
"#{build_dir}/gcc-#{gcc_version}.tar.xz",
sha256_sum: gcc_checksum
end
```
The `download` method downloads the file specified by the URL in the first
parameter, and writes it to the local file specified by the second parameter.
If the `:sha256sum` option is given, this causes two changes to the default
behavior:
* If Rscons finds the local file and it already has this checksum, then the
file will not be downloaded again.
* After downloading, Rscons verifies that the checksum matches what is given
and exits with an error if it does not.
###> PATH Management ###> PATH Management
`rscons` provides methods for management of the `PATH` environment variable. `rscons` provides methods for management of the `PATH` environment variable.
@ -1908,6 +1939,88 @@ env do |env|
end end
``` ```
### Example: GCC Cross Compiler
```ruby
binutils_version = "2.35"
binutils_checksum = "1b11659fb49e20e18db460d44485f09442c8c56d5df165de9461eb09c8302f85"
gcc_version = "10.2.0"
gcc_checksum = "b8dd4368bb9c7f0b98188317ee0254dd8cc99d1e3a18d0ff146c855fe16c1d8c"
install_path = File.expand_path("i686-elf-gcc")
target = "i686-elf"
path_prepend "#{install_path}/bin"
configure do
check_c_compiler "gcc"
check_program "make"
check_program "bison"
check_program "flex"
check_program "texi2any", on_fail: "Install the texinfo package"
check_program "wget"
check_lib "gmp", on_fail: "Install the libgmp-dev package"
check_lib "mpc", on_fail: "Install the libmpc-dev package"
check_lib "mpfr", on_fail: "Install the libmpfr-dev package"
end
default do
unless Dir.exist?(install_path)
# Download archives.
download "https://ftp.gnu.org/gnu/binutils/binutils-#{binutils_version}.tar.xz",
"#{build_dir}/binutils-#{binutils_version}.tar.xz",
sha256sum: binutils_checksum
download "https://ftp.gnu.org/gnu/gcc/gcc-#{gcc_version}/gcc-#{gcc_version}.tar.xz",
"#{build_dir}/gcc-#{gcc_version}.tar.xz",
sha256sum: gcc_checksum
# Extract archives.
sh "tar", "xJf", "binutils-#{binutils_version}.tar.xz",
chdir: build_dir
sh "tar", "xJf", "gcc-#{gcc_version}.tar.xz",
chdir: build_dir
# Build binutils.
rm_rf "#{build_dir}/build-binutils"
mkdir_p "#{build_dir}/build-binutils"
cd "#{build_dir}/build-binutils" do
sh %W[../binutils-#{binutils_version}/configure
--target=#{target} --prefix=#{install_path} --with-sysroot --disable-nls
--disable-werror]
sh "make"
sh "make install"
end
# Build gcc.
rm_rf "#{build_dir}/build-gcc"
mkdir_p "#{build_dir}/build-gcc"
cd "#{build_dir}/build-gcc" do
sh %W[../gcc-#{gcc_version}/configure
--target=#{target} --prefix=#{install_path} --disable-nls
--enable-languages=c,c++ --without-headers]
sh "make all-gcc"
sh "make all-target-libgcc"
sh "make install-gcc"
sh "make install-target-libgcc"
end
end
end
clean do
rm_f "#{build_dir}/binutils-#{binutils_version}.tar.xz"
rm_rf "#{build_dir}/binutils-#{binutils_version}"
rm_rf "#{build_dir}/build-binutils"
rm_f "#{build_dir}/gcc-#{gcc_version}.tar.xz"
rm_rf "#{build_dir}/gcc-#{gcc_version}"
rm_rf "#{build_dir}/build-gcc"
end
distclean do
rm_rf install_path
end
```
##> ./configure && make ##> ./configure && make
You can make your Rscons-based project more familiar to users of You can make your Rscons-based project more familiar to users of

View File

@ -42,6 +42,16 @@ module Rscons
@variant_groups = [] @variant_groups = []
end end
# Return if Rscons is in the task execution phase.
#
# @api private
#
# @return [Boolean]
# If Rscons is in the task execution phase.
def task_execution_phase?
@task_execution_phase
end
# Run the application. # Run the application.
# #
# Execute user-specified tasks. # Execute user-specified tasks.
@ -63,6 +73,7 @@ module Rscons
# Process exit code (0 on success). # Process exit code (0 on success).
def run(rsconscript, tasks_and_params, show_tasks, all_tasks, enabled_variants) def run(rsconscript, tasks_and_params, show_tasks, all_tasks, enabled_variants)
Cache.instance["failed_commands"] = [] Cache.instance["failed_commands"] = []
@tasks_and_params = tasks_and_params
@enabled_variants = enabled_variants @enabled_variants = enabled_variants
if enabled_variants == "" && !tasks_and_params.include?("configure") if enabled_variants == "" && !tasks_and_params.include?("configure")
if cache_enabled_variants = Cache.instance["configuration_data"]["enabled_variants"] if cache_enabled_variants = Cache.instance["configuration_data"]["enabled_variants"]
@ -70,13 +81,16 @@ module Rscons
end end
end end
@script = Script.new @script = Script.new
@script.load(rsconscript) if should_load_script
enable_variants @script.load(rsconscript)
enable_variants
end
if show_tasks if show_tasks
show_script_tasks(all_tasks) show_script_tasks(all_tasks)
return 0 return 0
end end
apply_task_params(tasks_and_params) apply_task_params(false)
@task_execution_phase = true
if tasks_and_params.empty? if tasks_and_params.empty?
check_process_environments check_process_environments
if Task.tasks["default"] if Task.tasks["default"]
@ -158,8 +172,8 @@ module Rscons
def distclean def distclean
cache = Cache.instance cache = Cache.instance
clean clean
FileUtils.rm_rf(@build_dir)
cache.clear cache.clear
FileUtils.rm_rf(@build_dir)
end end
# Check if the project needs to be configured. # Check if the project needs to be configured.
@ -168,6 +182,7 @@ module Rscons
# #
# @return [void] # @return [void]
def check_configure def check_configure
apply_task_params(true)
enable_variants enable_variants
unless Cache.instance["configuration_data"]["configured"] unless Cache.instance["configuration_data"]["configured"]
if @script.autoconf if @script.autoconf
@ -194,20 +209,20 @@ module Rscons
# #
# @api private # @api private
# #
# @param options [Hash]
# Options.
#
# @return [void] # @return [void]
def configure def configure
co = ConfigureOp.new(@script) unless @_configured
begin @_configured = true
@script.configure(co) co = ConfigureOp.new(@script)
rescue RsconsError => e begin
co.close(false) @script.configure(co)
raise e rescue RsconsError => e
co.close(false)
raise e
end
Cache.instance["configuration_data"]["enabled_variants"] = @enabled_variants
co.close(true)
end end
Cache.instance["configuration_data"]["enabled_variants"] = @enabled_variants
co.close(true)
end end
# Remove installed files. # Remove installed files.
@ -367,18 +382,27 @@ module Rscons
end end
end end
def apply_task_params(tasks_and_params) def apply_task_params(only_configure)
tasks_and_params.each do |task_name, task_params| @tasks_and_params.each do |task_name, task_params|
task_params.each do |param_name, param_value| unless only_configure && task_name != "configure"
if param = Task[task_name].params[param_name] task_params.each do |param_name, param_value|
Task[task_name].set_param_value(param_name, param_value) if param = Task[task_name].params[param_name]
else Task[task_name].set_param_value(param_name, param_value)
raise RsconsError.new("Unknown parameter #{param_name.inspect} for task #{task_name}") else
raise RsconsError.new("Unknown parameter #{param_name.inspect} for task #{task_name}")
end
end end
end end
end end
end end
def should_load_script
return true if @tasks_and_params.empty?
return true if Cache.instance["configuration_data"]["configured"]
return false if (@tasks_and_params.keys - %w[distclean clean uninstall]).empty?
true
end
end end
end end

View File

@ -101,6 +101,7 @@ module Rscons
# #
# @return [void] # @return [void]
def write def write
return unless Dir.exist?(File.dirname(cache_file))
@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))

View File

@ -23,14 +23,11 @@ module Rscons
$stdout.puts "Configuring project..." $stdout.puts "Configuring project..."
end end
end end
vars = {}
Task["configure"].params.each do |name, param| Task["configure"].params.each do |name, param|
unless Rscons.application.silent_configure unless Rscons.application.silent_configure
Ansi.write($stdout, "Setting #{name}... ", :green, param.value, :reset, "\n") Ansi.write($stdout, "Setting #{name}... ", :green, param.value, :reset, "\n")
end end
vars[name] = param.value
end end
store_merge(vars)
end end
# Close the log file handle. # Close the log file handle.
@ -65,7 +62,7 @@ module Rscons
ccc = %w[gcc clang] ccc = %w[gcc clang]
end end
cc = ccc.find do |cc| cc = ccc.find do |cc|
test_c_compiler(cc) test_c_compiler(cc, options)
end end
complete(cc ? 0 : 1, options.merge(success_message: cc)) complete(cc ? 0 : 1, options.merge(success_message: cc))
end end
@ -87,7 +84,7 @@ module Rscons
ccc = %w[g++ clang++] ccc = %w[g++ clang++]
end end
cc = ccc.find do |cc| cc = ccc.find do |cc|
test_cxx_compiler(cc) test_cxx_compiler(cc, options)
end end
complete(cc ? 0 : 1, options.merge(success_message: cc)) complete(cc ? 0 : 1, options.merge(success_message: cc))
end end
@ -109,7 +106,7 @@ module Rscons
cdc = %w[gdc ldc2] cdc = %w[gdc ldc2]
end end
dc = cdc.find do |dc| dc = cdc.find do |dc|
test_d_compiler(dc) test_d_compiler(dc, options)
end end
complete(dc ? 0 : 1, options.merge(success_message: dc)) complete(dc ? 0 : 1, options.merge(success_message: dc))
end end
@ -415,7 +412,7 @@ module Rscons
# #
# @return [Boolean] # @return [Boolean]
# Whether the C compiler tested successfully. # Whether the C compiler tested successfully.
def test_c_compiler(cc) def test_c_compiler(cc, options)
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh| File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
fh.puts <<-EOF fh.puts <<-EOF
int fun(int val) { int fun(int val) {
@ -427,7 +424,7 @@ module Rscons
merge = {"CC" => cc} merge = {"CC" => cc}
_, _, status = log_and_test_command(command) _, _, status = log_and_test_command(command)
if status == 0 if status == 0
store_merge(merge) store_merge(merge, options)
true true
end end
end end
@ -439,7 +436,7 @@ module Rscons
# #
# @return [Boolean] # @return [Boolean]
# Whether the C++ compiler tested successfully. # Whether the C++ compiler tested successfully.
def test_cxx_compiler(cc) def test_cxx_compiler(cc, options)
File.open("#{@work_dir}/cfgtest.cxx", "wb") do |fh| File.open("#{@work_dir}/cfgtest.cxx", "wb") do |fh|
fh.puts <<-EOF fh.puts <<-EOF
template<typename T> template<typename T>
@ -452,7 +449,7 @@ module Rscons
merge = {"CXX" => cc} merge = {"CXX" => cc}
_, _, status = log_and_test_command(command) _, _, status = log_and_test_command(command)
if status == 0 if status == 0
store_merge(merge) store_merge(merge, options)
true true
end end
end end
@ -464,7 +461,7 @@ module Rscons
# #
# @return [Boolean] # @return [Boolean]
# Whether the D compiler tested successfully. # Whether the D compiler tested successfully.
def test_d_compiler(dc) def test_d_compiler(dc, options)
File.open("#{@work_dir}/cfgtest.d", "wb") do |fh| File.open("#{@work_dir}/cfgtest.d", "wb") do |fh|
fh.puts <<-EOF fh.puts <<-EOF
import core.math; import core.math;
@ -493,7 +490,7 @@ module Rscons
end end
_, _, status = log_and_test_command(command) _, _, status = log_and_test_command(command)
if status == 0 if status == 0
store_merge(merge) store_merge(merge, options)
true true
end end
end end

View File

@ -72,24 +72,6 @@ module Rscons
attr_reader :name attr_reader :name
# Create an Environment object. # Create an Environment object.
#
# @overload initialize(name, options)
# @overload initialize(options)
#
# @param name [String]
# Environment name. This determines the folder name used to store all
# environment build files under the top-level build directory.
# @param options [Hash]
# @option options [Symbol] :echo
# :command, :short, or :off (default :short)
# @option options [Boolean] :exclude_builders
# Whether to omit adding default builders (default false)
# @option options [String, Array<String>] :use
# Use flag(s). If specified, any configuration flags which were saved
# with a corresponding `:use` value will be applied to this Environment.
#
# If a block is given, the Environment object is yielded to the block and
# when the block returns, the {#process} method is automatically called.
def initialize(*args, &block) def initialize(*args, &block)
@id = self.class.get_id @id = self.class.get_id
if args.first.is_a?(String) if args.first.is_a?(String)

View File

@ -102,9 +102,49 @@ module Rscons
end end
# Create an environment. # Create an environment.
#
# @overload env(name, options)
# @param name [String]
# Environment name. This determines the folder name used to store all
# environment build files under the top-level build directory.
# @param options [Hash]
# @option options [Symbol] :echo
# :command, :short, or :off (default :short)
# @option options [Boolean] :exclude_builders
# Whether to omit adding default builders (default false)
# @option options [String, Array<String>] :use
# Use flag(s). If specified, any configuration flags which were saved
# with a corresponding `:use` value will be applied to this
# Environment.
#
# @overload env(options)
# @param options [Hash]
# @option options [Symbol] :echo
# :command, :short, or :off (default :short)
# @option options [Boolean] :exclude_builders
# Whether to omit adding default builders (default false)
# @option options [String, Array<String>] :use
# Use flag(s). If specified, any configuration flags which were saved
# with a corresponding `:use` value will be applied to this
# Environment.
#
# If a block is given it is immediately executed and passed the newly
# created Environment object as an argument.
# If the Environment is created in task context, the +process+ method is
# immediately called.
# Otherwise, the Environment is not processed until the task execution
# phase.
#
# @yield [env]
# @yieldparam env [Environment]
# The created environment.
def env(*args, &block) def env(*args, &block)
Rscons.application.check_configure Rscons.application.check_configure
Environment.new(*args, &block) e = Environment.new(*args, &block)
if Rscons.application.task_execution_phase?
e.process
end
e
end end
# Construct a task parameter. # Construct a task parameter.

View File

@ -1,4 +1,4 @@
module Rscons module Rscons
# Project version. # Project version.
VERSION = "2.3.0" VERSION = "3.0.2"
end end

View File

@ -60,7 +60,13 @@ combined_file.each do |line|
end end
end end
license = File.read("LICENSE.txt").gsub(/^/, "# ") license = File.read("LICENSE.txt").gsub(/^(.*?)$/) do |line|
if line.size > 0
"# #{line}"
else
"#"
end
end
require "zlib" require "zlib"
require "base64" require "base64"

View File

@ -195,6 +195,14 @@ 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 "processes the environment when created within a task" do
test_dir("simple")
result = run_rscons(args: %w[-f env_in_task.rb])
expect(result.stderr).to eq ""
expect(File.exists?("build/e.1/simple.c.o")).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
end
it "uses the build directory specified with -b" do it "uses the build directory specified with -b" do
test_dir("simple") test_dir("simple")
result = run_rscons(args: %w[-b b]) result = run_rscons(args: %w[-b b])
@ -350,7 +358,7 @@ EOF
expect(result.stderr).to match /Could not find a registered build target "foo"/ expect(result.stderr).to match /Could not find a registered build target "foo"/
end end
context "clean operation" do context "clean task" do
it 'cleans built files' do it 'cleans built files' do
test_dir("simple") test_dir("simple")
result = run_rscons result = run_rscons
@ -364,6 +372,28 @@ EOF
expect(File.exists?('simple.c')).to be_truthy expect(File.exists?('simple.c')).to be_truthy
end end
it "executes custom clean action blocks" do
test_dir("simple")
result = run_rscons(args: %w[-f clean.rb])
expect(result.stderr).to eq ""
expect(File.exists?("build/e.1/simple.c.o")).to be_truthy
result = run_rscons(args: %w[-f clean.rb clean])
expect(result.stderr).to eq ""
expect(result.stdout).to match %r{custom clean action}
expect(File.exists?("build/e.1/simple.c.o")).to be_falsey
end
it "does not process environments" do
test_dir("simple")
result = run_rscons(args: %w[clean])
expect(result.stderr).to eq ""
expect(File.exists?('build/e.1/simple.c.o')).to be_falsey
expect(File.exists?('build/e.1')).to be_falsey
expect(File.exists?('simple.exe')).to be_falsey
expect(File.exists?('simple.c')).to be_truthy
expect(result.stdout).to eq ""
end
it 'does not clean created directories if other non-rscons-generated files reside there' do it 'does not clean created directories if other non-rscons-generated files reside there' do
test_dir("simple") test_dir("simple")
result = run_rscons result = run_rscons
@ -546,14 +576,16 @@ EOF
result = run_rscons result = run_rscons
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.c.o -MMD -MF build/e.1/one.c.o.mf -Dmake_lib one.c},
%r{gcc -c -o build/e.1/two.c.o -MMD -MF build/e.1/two.c.o.mf -Dmake_lib two.c}, %r{gcc -c -o build/e.1/two.c.o -MMD -MF build/e.1/two.c.o.mf -Dmake_lib two.c},
%r{ar rcs lib.a build/e.1/one.c.o build/e.1/two.c.o}, %r{gcc -c -o build/e.1/three.c.o -MMD -MF build/e.1/three.c.o.mf -Dmake_lib three.c},
%r{gcc -c -o build/e.1/three.c.o -MMD -MF build/e.1/three.c.o.mf three.c}, %r{ar rcs libmylib.a build/e.1/two.c.o build/e.1/three.c.o},
%r{gcc -o library.exe lib.a build/e.1/three.c.o}, %r{gcc -c -o build/e.1/one.c.o -MMD -MF build/e.1/one.c.o.mf one.c},
%r{gcc -o library.exe build/e.1/one.c.o -L. -lmylib},
]) ])
expect(File.exists?("library.exe")).to be_truthy expect(File.exists?("library.exe")).to be_truthy
expect(nr(`ar t lib.a`)).to eq "one.c.o\ntwo.c.o\n" ar_t = nr(`ar t libmylib.a`)
expect(ar_t).to match %r{\btwo.c.o\b}
expect(ar_t).to match %r{\bthree.c.o\b}
end end
it 'supports build hooks to override construction variables' do it 'supports build hooks to override construction variables' do
@ -1645,7 +1677,7 @@ EOF
test_dir("library") test_dir("library")
result = run_rscons(args: %w[-f override_arcmd.rb]) result = run_rscons(args: %w[-f override_arcmd.rb])
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [%r{ar rcf lib.a build/e.1/one.c.o build/e.1/three.c.o build/e.1/two.c.o}]) verify_lines(lines(result.stdout), [%r{ar rc lib.a build/e.1/one.c.o build/e.1/three.c.o build/e.1/two.c.o}])
end end
it "allows passing object files as sources" do it "allows passing object files as sources" do
@ -1690,7 +1722,7 @@ EOF
]) ])
expect(File.exist?("simple.exe")).to be_truthy expect(File.exist?("simple.exe")).to be_truthy
expect(File.exist?("simple.size")).to be_truthy expect(File.exist?("simple.size")).to be_truthy
expect(File.read("simple.size")).to match /text.*data.*bss/ expect(File.read("simple.size")).to match /text.*data/i
end end
end end
@ -1788,7 +1820,7 @@ EOF
end end
end end
context "configure operation" do context "configure task" do
it "does not print configuring messages when no configure block and configure task not called" do it "does not print configuring messages when no configure block and configure task not called" do
test_dir "configure" test_dir "configure"
result = run_rscons(args: %w[-f no_configure_output.rb]) result = run_rscons(args: %w[-f no_configure_output.rb])
@ -1804,7 +1836,52 @@ 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 it "only runs the configure operation once" do
test_dir "configure"
result = run_rscons(args: %w[-f configure_with_top_level_env.rb configure])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to_not match %r{Configuring project.*Configuring project}m
end
it "loads configure parameters before invoking configure" do
test_dir "configure"
result = run_rscons(args: %w[-f configure_with_top_level_env.rb configure --prefix=/yodabob])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to match "Prefix is /yodabob"
end
it "does not configure for distclean operation" do
test_dir "configure"
result = run_rscons(args: %w[-f configure_with_top_level_env.rb distclean])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to_not match %r{Configuring project}
end
it "does not configure for clean operation" do
test_dir "configure"
result = run_rscons(args: %w[-f configure_with_top_level_env.rb clean])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to_not match %r{Configuring project}
end
it "does not configure for uninstall operation" do
test_dir "configure"
result = run_rscons(args: %w[-f configure_with_top_level_env.rb uninstall])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to_not match %r{Configuring project}
end
it "automatically runs the configure task if the project is not yet configured in the given build directory" do
test_dir "configure" test_dir "configure"
result = run_rscons(args: %w[-f check_c_compiler.rb]) result = run_rscons(args: %w[-f check_c_compiler.rb])
@ -1863,6 +1940,17 @@ EOF
end end
end end
it "respects use flag" do
test_dir "configure"
result = run_rscons(args: %w[-f check_c_compiler_use.rb -v])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to match %r{\bgcc .*/t1/}
expect(result.stdout).to_not match %r{\bclang .*/t1/}
expect(result.stdout).to match %r{\bclang .*/t2/}
expect(result.stdout).to_not match %r{\bgcc .*/t2/}
end
it "successfully tests a compiler with an unknown name" do it "successfully tests a compiler with an unknown name" do
test_dir "configure" test_dir "configure"
create_exe "mycompiler", %[exec gcc "$@"] create_exe "mycompiler", %[exec gcc "$@"]
@ -1906,6 +1994,17 @@ EOF
end end
end end
it "respects use flag" do
test_dir "configure"
result = run_rscons(args: %w[-f check_cxx_compiler_use.rb -v])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to match %r{\bg\+\+ .*/t1/}
expect(result.stdout).to_not match %r{\bclang\+\+ .*/t1/}
expect(result.stdout).to match %r{\bclang\+\+ .*/t2/}
expect(result.stdout).to_not match %r{\bg\+\+ .*/t2/}
end
it "successfully tests a compiler with an unknown name" do it "successfully tests a compiler with an unknown name" do
test_dir "configure" test_dir "configure"
create_exe "mycompiler", %[exec clang++ "$@"] create_exe "mycompiler", %[exec clang++ "$@"]
@ -1951,6 +2050,17 @@ EOF
end end
end end
it "respects use flag" do
test_dir "configure"
result = run_rscons(args: %w[-f check_d_compiler_use.rb -v])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to match %r{\bgdc .*/t1/}
expect(result.stdout).to_not match %r{\bldc2 .*/t1/}
expect(result.stdout).to match %r{\bldc2 .*/t2/}
expect(result.stdout).to_not match %r{\bgdc .*/t2/}
end
unless RUBY_PLATFORM =~ /mingw|msys/ unless RUBY_PLATFORM =~ /mingw|msys/
it "successfully tests a compiler with an unknown name that uses gdc-compatible options" do it "successfully tests a compiler with an unknown name that uses gdc-compatible options" do
test_dir "configure" test_dir "configure"
@ -2228,7 +2338,7 @@ EOF
context "check_cfg" do context "check_cfg" do
context "when passed a package" do context "when passed a package" do
it "stores flags and uses them during a build operation" do it "stores flags and uses them during a build" do
test_dir "configure" test_dir "configure"
create_exe "pkg-config", "echo '-DMYPACKAGE'" create_exe "pkg-config", "echo '-DMYPACKAGE'"
result = run_rscons(args: %w[-f check_cfg_package.rb configure]) result = run_rscons(args: %w[-f check_cfg_package.rb configure])
@ -2265,7 +2375,7 @@ EOF
end end
context "when passed a program" do context "when passed a program" do
it "stores flags and uses them during a build operation" do it "stores flags and uses them during a build" do
test_dir "configure" test_dir "configure"
create_exe "my-config", "echo '-DMYCONFIG -lm'" create_exe "my-config", "echo '-DMYCONFIG -lm'"
result = run_rscons(args: %w[-f check_cfg.rb configure]) result = run_rscons(args: %w[-f check_cfg.rb configure])
@ -2504,15 +2614,15 @@ EOF
end end
end end
context "install operation" do context "install task" do
it "invokes a configure operation if the project is not yet configured" do it "invokes the configure task if the project is not yet configured" do
test_dir "typical" test_dir "typical"
result = run_rscons(args: %w[-f install.rb install]) result = run_rscons(args: %w[-f install.rb install])
expect(result.stdout).to match /Configuring install_test/ expect(result.stdout).to match /Configuring install_test/
end end
it "invokes a build operation" do it "invokes a build dependency" do
test_dir "typical" test_dir "typical"
Dir.mktmpdir do |prefix| Dir.mktmpdir do |prefix|
@ -2572,7 +2682,7 @@ EOF
end end
end end
context "uninstall operation" do context "uninstall task" do
it "removes installed files but not built files" do it "removes installed files but not built files" do
test_dir "typical" test_dir "typical"