Compare commits

..
26 Commits
Author SHA1 Message Date
josh a19c2e908e Update gems 2025-03-24 09:48:10 -04:00
josh 5223dfe211 Add base64 to Gemfile 2025-01-15 20:18:41 -05:00
josh d0c1b01598 Update gems 2024-03-28 09:11:07 -04:00
josh 57db93c59b Add LLVM support to documentation 2024-03-24 11:00:15 -04:00
josh ba71e8d5e3 Add support for building object files from LLVM assembly sources - close #175 2024-03-23 22:24:45 -04:00
josh 6e7139abb1 v3.2.0 2024-03-18 22:05:52 -04:00
josh 896a3e270f Indent docstrings under @overload 2024-03-18 22:05:10 -04:00
josh 3ee0015cef Update UPGRADING notes for v3.2.0 2024-03-18 21:53:04 -04:00
josh 0315729f69 Update CHANGELOG for v3.2.0 2024-03-18 21:45:43 -04:00
josh 8c865e668b Add upgrading instructions - close #167 2024-03-17 20:36:59 -04:00
josh 150960246b Improve DSL method documentation - close #164 2024-03-17 20:08:06 -04:00
josh c2277bc0a1 Update gems 2024-03-01 15:11:39 -05:00
josh 4baf26e492 Update ERB call to avoid deprecation warnings 2024-02-28 16:14:21 -05:00
josh 6044b64695 Update gems 2024-02-28 16:11:09 -05:00
josh 415fa424d1 Fix configuration checks performed with ldc2 compiler - close #172 2024-02-04 20:25:01 -05:00
josh f8c21a9bcc Use top-level build directory as environment build directory for unnamed environments - close #170 2023-09-10 21:41:42 -04:00
josh 6a8647a933 Place object files next to source files for source files in build directory - close #171 2023-09-10 10:00:41 -04:00
josh 3867133e89 Cannot output binary to an environment's build root with the same name as the top-level source directory - close #168 2023-09-10 08:51:03 -04:00
josh a7b962c11a Output a better error when pkg-config is not found - close #169 2023-09-08 21:05:01 -04:00
josh b490daa480 Update gems 2023-07-28 14:03:39 -04:00
josh ed7408367f Replace CFile builder with Yacc and Lex builders - close #166 2023-02-22 20:57:00 -05:00
josh d4ec07dd7a Fix user guide examples for task dependencies 2022-10-14 16:18:14 -04:00
josh 33b606ccb1 v3.1.0 2022-08-11 14:57:26 -04:00
josh c48526fd97 Improve configuration error messages - close #162 2022-08-11 14:41:29 -04:00
josh 419e6ed313 builder registered during build hooks should increase build step count - close #161 2022-08-05 17:05:13 -04:00
josh 132d22e886 Ruby 3.2 compatibility - close #163 2022-08-05 16:40:48 -04:00
48 changed files with 761 additions and 339 deletions

No files matched your search

+27
View File
@@ -1,3 +1,30 @@
## v3.2.0
### New Features
- #171 - Place object files next to source files for source files in build directory
- #170 - Use top-level build directory as environment build directory for unnamed environments
- #167 - Add upgrading instructions
- #166 - Replace CFile builder with Yacc and Lex builders
### Fixes
- #172 - Fix configuration checks performed with ldc2 compiler
- #169 - Output a better error when pkg-config is not found
- #168 - Cannot output binary to an environment's build root with the same name as the top-level source directory
- #164 - Improve DSL method documentation
## v3.1.0
### New Features
- #162 - Improve configuration error messages
- #163 - Ruby 3.2 compatibility
### Fixes
- #161 - builder registered during build hooks should increase build step count
## v3.0.2
### Fixes
+1 -1
View File
@@ -9,6 +9,6 @@ To run the rscons specs, the following commands must be available:
* g++
* clang++
* gdc
* ldc
* ldc2
* flex
* bison
+1
View File
@@ -1,5 +1,6 @@
source 'https://rubygems.org'
gem "base64"
gem "rspec"
gem "rake"
gem "simplecov", "~> 0.15.0"
+24 -22
View File
@@ -1,44 +1,46 @@
GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.5.0)
base64 (0.2.0)
date (3.4.1)
diff-lcs (1.6.0)
docile (1.1.5)
json (2.6.1)
psych (4.0.3)
json (2.10.2)
psych (5.2.3)
date
stringio
rake (13.0.6)
rdoc (6.4.0)
rake (13.2.1)
rdoc (6.13.0)
psych (>= 4.0.0)
redcarpet (3.5.1)
rspec (3.11.0)
rspec-core (~> 3.11.0)
rspec-expectations (~> 3.11.0)
rspec-mocks (~> 3.11.0)
rspec-core (3.11.0)
rspec-support (~> 3.11.0)
rspec-expectations (3.11.0)
redcarpet (3.6.1)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.3)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-mocks (3.11.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-support (3.11.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.2)
simplecov (0.15.1)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
stringio (3.0.1)
stringio (3.1.5)
syntax (1.2.2)
webrick (1.7.0)
yard (0.9.27)
webrick (~> 1.7.0)
yard (0.9.37)
PLATFORMS
ruby
x86-mingw32
DEPENDENCIES
base64
json
rake
rdoc
@@ -49,4 +51,4 @@ DEPENDENCIES
yard
BUNDLED WITH
2.2.31
2.4.17
+1 -1
View File
@@ -9,7 +9,7 @@ It supports the following features:
* multi-threaded job execution
* auto-configuration
* built-in builders for several common operations
* out-of-the-box support for C, C++, and D languages
* out-of-the-box support for Assembly, C, C++, D, and LLVM
* extensibility for other languages or custom builders
* compatible with Windows, Linux, OS X, and FreeBSD
* colorized output with build progress
+10
View File
@@ -0,0 +1,10 @@
# Upgrading
## v3.2.0
- Replace any calls to `env.CFile()` builder with `env.Lex()` or `env.Yacc()` as required.
## v3.0.0
- Move `build` block contents outside of `build` block and remove `build` call.
- Replace `Environment.new()` calls with `env()`.
-4
View File
@@ -1,4 +0,0 @@
env do |env|
env.CFile("lexer.c", "lexer.l")
env.CFile("parser.c", "parser.y")
end
@@ -1,3 +0,0 @@
env do |env|
env.CFile("file.c", "foo.bar")
end
+2 -2
View File
@@ -1,10 +1,10 @@
debug = env(echo: :command) do |env|
debug = env("dbg", echo: :command) do |env|
env['CFLAGS'] = '-O2'
env['CPPFLAGS'] = '-DSTRING="Debug Version"'
env.Program('program-debug.exe', Dir['src/*.c'])
end
release = debug.clone do |env|
release = debug.clone("rls") do |env|
env["CPPFLAGS"] = '-DSTRING="Release Version"'
env.Program('program-release.exe', Dir['src/*.c'])
end
+2 -2
View File
@@ -1,4 +1,4 @@
env1 = env(echo: :command) do |env|
env1 = env("e1", echo: :command) do |env|
env['CFLAGS'] = '-O2'
env.add_build_hook do |builder|
builder.vars['CPPFLAGS'] = '-DSTRING="Hello"'
@@ -9,6 +9,6 @@ env1 = env(echo: :command) do |env|
env.Program('program.exe', Dir['src/*.c'])
end
env2 = env1.clone do |env|
env2 = env1.clone("e2") do |env|
env.Program('program2.exe', Dir['src/*.c'])
end
@@ -0,0 +1,5 @@
ENV["PATH"] = ""
configure do
check_cfg package: "mypackage"
end
@@ -1,3 +1,3 @@
configure do
check_d_compiler "gdc", "ldc2"
check_d_compiler "gdc", "ldc2", "ldc"
end
@@ -0,0 +1,8 @@
configure do
check_d_compiler "ldc2"
check_lib "z"
end
env(echo: :command) do |env|
env.Program("simple.exe", "simple.d")
end
+4
View File
@@ -0,0 +1,4 @@
env do |env|
env.Lex("lexer.c", "lexer.l")
env.Yacc("parser.c", "parser.y")
end
File renamed without changes.
File renamed without changes.
+4
View File
@@ -0,0 +1,4 @@
env do |env|
env["LLVMAS_FLAGS"] += %w[-Wno-override-module]
env.Program("llvmtest.exe", %w[main.c one.ll])
end
+8
View File
@@ -0,0 +1,8 @@
configure do
check_c_compiler "clang"
end
env do |env|
env["LLVMAS_FLAGS"] += %w[-Wno-override-module]
env.Program("llvmtest.exe", %w[one.ll two.ll main2.c], direct: true)
end
+6
View File
@@ -0,0 +1,6 @@
extern int one(void);
int main(int argc, char * argv[])
{
return one();
}
+9
View File
@@ -0,0 +1,9 @@
extern int one(void);
extern int two(void);
int main(int argc, char * argv[])
{
one();
two();
return 0;
}
+9
View File
@@ -0,0 +1,9 @@
@str = private unnamed_addr constant [12 x i8] c"hello world\00"
declare i32 @puts(ptr nocapture) nounwind
define i32 @one()
{
call i32 @puts(ptr @str)
ret i32 0
}
+9
View File
@@ -0,0 +1,9 @@
@str = private unnamed_addr constant [12 x i8] c"hello again\00"
declare i32 @puts(ptr nocapture) nounwind
define i32 @two()
{
call i32 @puts(ptr @str)
ret i32 0
}
@@ -0,0 +1,13 @@
env("e", echo: :command) do |env|
source_file = "#{env.build_root}/src/foo.c"
FileUtils.mkdir_p(File.dirname(source_file))
File.open(source_file, "w") do |fh|
fh.puts(<<-EOF)
int main()
{
return 29;
}
EOF
end
env.Program("foo.exe", source_file)
end
@@ -1,7 +1,7 @@
class MyObject < Rscons::Builder
def run(options)
if @builder
if File.exists?(@target)
if File.exist?(@target)
true
else
false
+1 -1
View File
@@ -4,7 +4,7 @@ class TestBuilder < Rscons::Builder
true
else
if @target == "two"
return false unless File.exists?("one")
return false unless File.exist?("one")
end
wait_time = @env.expand_varref("${wait_time}", @vars)
@command = ["ruby", "-e", "require 'fileutils'; sleep #{wait_time}; FileUtils.touch('#{@target}');"]
@@ -0,0 +1,4 @@
env "src" do |env|
env["CPPPATH"] += glob("src/**")
env.Program("^/src", glob("src/**/*.c"))
end
@@ -0,0 +1,13 @@
variant "debug"
variant "release"
with_variants do
env do |env|
if variant("debug")
env["CPPDEFINES"] << "DEBUG"
else
env["CPPDEFINES"] << "NDEBUG"
end
env.Program("^/prog.exe", "prog.c")
end
end
+101 -33
View File
@@ -6,7 +6,7 @@ It supports the following features:
* multi-threaded job execution
* auto-configuration
* built-in builders for several common operations
* out-of-the-box support for C, C++, and D languages
* out-of-the-box support for Assembly, C, C++, D, and LLVM
* extensibility for other languages or custom builders
* compatible with Windows, Linux, OS X, and FreeBSD
* colorized output with build progress
@@ -265,21 +265,17 @@ which they were added.
Example:
```ruby
task "build" do
env do |env|
env.Program("^^/proj.elf", glob("src/**/*.c"))
end
proj_env = env do |env|
env.Program("^/proj.elf", glob("src/**/*.c"))
end
task "flash", deps: "build" do
sh "nrfjprog", "-f", "NRF52", "--program", env.expand("^^/proj.elf")
task "flash" do
sh "nrfjprog", "-f", "NRF52", "--program", proj_env.expand("^/proj.elf")
end
```
In this example, the `flash` task depends on the `build` task.
So if the project had not yet been built, and the user executes
`./rscons flash`, the project would first be built and then flashed to the
target.
In this example, the `flash` task would first build the proj.elf target and
then flash it to target with the nrfjprog program.
If the `task` method is called again with the name of an already existing task,
the task is not overwritten, but rather modified.
@@ -287,6 +283,34 @@ 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.
For example, with the `Rsconscript`:
```ruby
task "a" do
puts "A"
end
task "b" do
puts "B"
end
task "c", depends: "a" do
puts "C1"
end
task "c", depends: "b" do
puts "C2"
end
```
The following behavior is observed:
$ ./rscons c
A
B
C1
C2
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}).
@@ -378,7 +402,7 @@ argument (task name) automatically filled in by the shortcut method.
For example:
```ruby
default deps: "unpack_compiler" do
default depends: "unpack_compiler" do
puts "default task"
end
```
@@ -386,7 +410,7 @@ end
is equivalent to:
```ruby
task "default", deps: "unpack_compiler" do
task "default", depends: "unpack_compiler" do
puts "default task"
end
```
@@ -463,11 +487,11 @@ task "build" do
...
end
task "flash" do
task "flash", depends: "build" do
...
end
default deps: "build"
default depends: "build"
```
Then when the user runs `./rscons` the "build" task will be executed.
@@ -901,11 +925,11 @@ There are several default builders that are built-in to Rscons:
* `Command`, which executes a user-defined command to produce the target.
* `Copy`, which copies files or directories to a specified destination.
* `CFile`, which builds a C or C++ source file from a lex or yacc input file.
* `Directory`, which creates a directory.
* `Disassemble`, which disassembles an object file to a disassembly listing.
* `Install`, which installs files or directories to a specified destination.
* `InstallDirectory`, which creates a directory in an install destination.
* `Lex`, which builds a source file from a lex input file.
* `Library`, which collects object files into a static library archive file.
* `Object`, which compiles source files to produce an object file.
* `Preprocess`, which invokes the C/C++ preprocessor on a source file.
@@ -915,6 +939,7 @@ There are several default builders that are built-in to Rscons:
* `SharedObject`, which compiles source files to produce an object file, in a
way that is able to be used to create a shared library.
* `Size`, which runs the 'size' utility on an executable file.
* `Yacc`, which builds a source file from a yacc input file.
####> The Command Builder
@@ -941,17 +966,6 @@ The `Command` builder supports the following construction variables:
`CMD_STDOUT` is expanded for variable references, so the token `${_TARGET}`
can be used, for example.
####> The CFile Builder
```ruby
env.CFile(target, source)
# Example
env.CFile("^/parser/parser.c", "parser.y")
```
The `CFile` builder will generate a C or C++ source file from a lex (.l, .ll)
or yacc (.y, .yy) input file.
####> The Copy Builder
```ruby
@@ -1024,6 +1038,17 @@ the `InstallDirectory` builder.
The `uninstall` task removes targets created by the `InstallDirectory` builder
but not by the `Directory` builder.
####> The Lex Builder
```ruby
env.Lex(target, source)
# Example
env.Lex("^/lexer.c", "lexer.l")
```
The `Lex` builder will generate a source file from a lex (.l, .ll)
input file.
####> The Library Builder
```ruby
@@ -1154,6 +1179,17 @@ 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`.
####> The Yacc Builder
```ruby
env.Yacc(target, source)
# Example
env.Yacc("^/parser.c", "parser.y")
```
The `Yacc` builder will generate a source file from a yacc (.y, .yy)
input file.
###> Phony Targets
Rscons supports phony build targets.
@@ -1272,10 +1308,10 @@ 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.
Each `env` method 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 "-".
Environment's build directory name has the active variant(s) keys appended to
the given Environment name, 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
@@ -1284,6 +1320,29 @@ 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.
The key for a variant is the variant's name by default but can be overridden by
passing a `:key` value to the `variant` method.
A `nil` value for the `:key` parameter will omit that variant from appearing
in the environment's build directory name.
For example:
```ruby
variant "debug"
variant "release", key: nil
with_variants do
env "prog" do |env|
end
end
```
In this example, one "prog" environment will be created for the "debug" variant
with the build directory "prog-debug", and another "prog" environment will be
created for the "release" variant with the build directory "prog".
The build directory for the release variant of the "prog" environment is just
"prog" instead of "prog-release" because the key for the "release" variant is
set to `nil`.
Variants are enabled by default, but can be disabled by passing a `false` value
to the `:default` option of the `variant` method.
For example:
@@ -1558,8 +1617,8 @@ end
The `Object` and `SharedObject` builders that ship with Rscons have an API that
allows the user to register extra languages that can be suppored by the
builders.
In fact, the built-in support for assembly, C, C++, and D compilation all make
use of this built-in API.
In fact, the built-in support for assembly, C, C++, D, and LLVM compilation
all make use of this built-in API.
To see an example of how this API is used, see the
`lib/rscons/builders/lang/*.rb` files in the Rscons source repository.
For example, here is how the C++ language is registered:
@@ -1868,6 +1927,15 @@ env do |env|
end
```
### Example: Building a Program from C and LLVM Sources
```ruby
env do |env|
env["CFLAGS"] << "-Wall"
env.Program("program", glob("src/**/*.{c,ll}"))
end
```
### Example: Cloning an Environment
```ruby
@@ -1935,7 +2003,7 @@ end
```ruby
env do |env|
env.CFile("^/parser.tab.cc", "parser.yy")
env.Yacc("^/parser.tab.cc", "parser.yy")
end
```
+5 -2
View File
@@ -23,13 +23,13 @@ module Rscons
# Names of the default builders which will be added to all newly created
# {Environment} objects.
DEFAULT_BUILDERS = [
:CFile,
:Command,
:Copy,
:Directory,
:Disassemble,
:Install,
:InstallDirectory,
:Lex,
:Library,
:Object,
:Preprocess,
@@ -37,6 +37,7 @@ module Rscons
:SharedLibrary,
:SharedObject,
:Size,
:Yacc,
]
# Class to represent a fatal error during an Rscons operation.
@@ -135,11 +136,11 @@ require_relative "rscons/builders/mixins/object_deps"
require_relative "rscons/builders/mixins/program"
# default builders
require_relative "rscons/builders/cfile"
require_relative "rscons/builders/command"
require_relative "rscons/builders/copy"
require_relative "rscons/builders/directory"
require_relative "rscons/builders/disassemble"
require_relative "rscons/builders/lex"
require_relative "rscons/builders/library"
require_relative "rscons/builders/object"
require_relative "rscons/builders/preprocess"
@@ -148,12 +149,14 @@ require_relative "rscons/builders/shared_library"
require_relative "rscons/builders/shared_object"
require_relative "rscons/builders/simple_builder"
require_relative "rscons/builders/size"
require_relative "rscons/builders/yacc"
# language support
require_relative "rscons/builders/lang/asm"
require_relative "rscons/builders/lang/c"
require_relative "rscons/builders/lang/cxx"
require_relative "rscons/builders/lang/d"
require_relative "rscons/builders/lang/llvm_asm"
# Unbuffer $stdout
$stdout.sync = true
+18 -1
View File
@@ -237,7 +237,7 @@ module Rscons
cache = Cache.instance
cache.targets(true).each do |target|
cache.remove_target(target)
next unless File.exists?(target)
next unless File.exist?(target)
puts "Removing #{target}" if verbose
FileUtils.rm_f(target)
end
@@ -258,6 +258,14 @@ module Rscons
#
# @param name [String]
# Variant name.
# @param options [Hash]
# Optional parameters.
# @option options [String] :default
# Whether the variant is enabled by default (default: true).
# @option options [String] :key
# Variant key, used to name an Environment's build directory. If nil,
# this variant will not contribute to the Environment's build directory
# name.
def variant(name, options = {})
if @active_variants
!!@active_variants.find {|variant| variant[:name] == name}
@@ -294,6 +302,15 @@ module Rscons
end
# Create a variant group.
#
# @overload variant_group(name, options = {})
# @param name [String]
# Variant group name (optional).
# @param options [Hash]
# Optional variant group parameters.
# @overload variant_group(options = {})
# @param options [Hash]
# Optional variant group parameters.
def variant_group(*args, &block)
if args.first.is_a?(String)
name = args.slice!(0)
-35
View File
@@ -1,35 +0,0 @@
module Rscons
module Builders
# Build a C or C++ source file given a lex (.l, .ll) or yacc (.y, .yy)
# input file.
#
# Examples::
# env.CFile("parser.tab.cc", "parser.yy")
# env.CFile("lex.yy.cc", "parser.ll")
class CFile < Builder
# Run the builder to produce a build target.
def run(options)
if @command
finalize_command
else
@vars["_TARGET"] = @target
@vars["_SOURCES"] = @sources
case
when @sources.first.end_with?(*@env.expand_varref("${LEXSUFFIX}"))
cmd = "LEX"
message = "Generating lexer"
when @sources.first.end_with?(*@env.expand_varref("${YACCSUFFIX}"))
cmd = "YACC"
message = "Generating parser"
else
raise "Unknown source file #{@sources.first.inspect} for CFile builder"
end
command = @env.build_command("${#{cmd}_CMD}", @vars)
standard_command("#{message} from <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
end
end
end
end
end
+4 -4
View File
@@ -14,14 +14,14 @@ module Rscons
# Run the builder to produce a build target.
def run(options)
target_is_dir = (@sources.length > 1) ||
Dir.exists?(@sources.first) ||
Dir.exists?(@target)
Dir.exist?(@sources.first) ||
Dir.exist?(@target)
outdir = target_is_dir ? @target : File.dirname(@target)
# Collect the list of files to copy over.
file_map = {}
if target_is_dir
@sources.each do |src|
if Dir.exists? src
if Dir.exist? src
Dir.glob("#{src}/**/*", File::FNM_DOTMATCH).select do |f|
File.file?(f)
end.each do |subfile|
@@ -50,7 +50,7 @@ module Rscons
end
@cache.register_build(dest, :Copy, [src], @env, install: @install_builder)
end
(target_is_dir ? Dir.exists?(@target) : File.exists?(@target)) ? true : false
(target_is_dir ? Dir.exist?(@target) : File.exist?(@target)) ? true : false
end
end
+1 -1
View File
@@ -14,7 +14,7 @@ module Rscons
def run(options)
if File.directory?(@target)
true
elsif File.exists?(@target)
elsif File.exist?(@target)
Ansi.write($stderr, :red, "Error: `#{@target}' already exists and is not a directory", :reset, "\n")
false
else
+10
View File
@@ -0,0 +1,10 @@
Rscons::Builders::Object.register(
command: "${LLVMAS_CMD}",
direct_command: "${LLVMAS_CMD:direct}",
suffix: "${LLVMAS_SUFFIX}",
short_description: "Assembling")
Rscons::Builders::SharedObject.register(
command: "${LLVMAS_CMD}",
direct_command: "${LLVMAS_CMD:direct}",
suffix: "${LLVMAS_SUFFIX}",
short_description: "Assembling")
+24
View File
@@ -0,0 +1,24 @@
module Rscons
module Builders
# Build a source file given a lex input file.
#
# Examples::
# env.Lex("lex.c", "parser.l")
# env.Lex("lex.cc", "parser.ll")
class Lex < Builder
# Run the builder to produce a build target.
def run(options)
if @command
finalize_command
else
@vars["_TARGET"] = @target
@vars["_SOURCES"] = @sources
command = @env.build_command("${LEX_CMD}", @vars)
standard_command("Generating lexer source from <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
end
end
end
end
end
+1 -1
View File
@@ -8,7 +8,7 @@ module Rscons
# dependency file.
def finalize_command_with_depfile
deps = @sources
if File.exists?(@vars["_DEPFILE"])
if File.exist?(@vars["_DEPFILE"])
deps += Util.parse_dependency_file(@vars["_DEPFILE"])
end
@cache.register_build(@target, @command, deps.uniq, @env)
+24
View File
@@ -0,0 +1,24 @@
module Rscons
module Builders
# Build a source file given a yacc input file.
#
# Examples::
# env.Yacc("parser.c", "parser.y")
# env.Yacc("parser.cc", "parser.yy")
class Yacc < Builder
# Run the builder to produce a build target.
def run(options)
if @command
finalize_command
else
@vars["_TARGET"] = @target
@vars["_SOURCES"] = @sources
command = @env.build_command("${YACC_CMD}", @vars)
standard_command("Generating parser source from <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
end
end
end
end
end
+2 -2
View File
@@ -147,7 +147,7 @@ module Rscons
unless Rscons.phony_target?(target)
# target file must exist on disk
unless File.exists?(target)
unless File.exist?(target)
if options[:debug]
puts "Target #{target} needs rebuilding because it does not exist on disk"
end
@@ -307,7 +307,7 @@ module Rscons
parts.each_index do |i|
next if parts[i] == ""
subpath = File.join(*parts[0, i + 1])
unless File.exists?(subpath)
unless File.exist?(subpath)
FileUtils.mkdir_p(subpath)
@cache["directories"][subpath] = !!options[:install]
end
+2 -2
View File
@@ -118,13 +118,13 @@ module Rscons
# Find the build script.
if rsconscript
unless File.exists?(rsconscript)
unless File.exist?(rsconscript)
$stderr.puts "Cannot read #{rsconscript}"
return 1
end
else
rsconscript = DEFAULT_RSCONSCRIPTS.find do |f|
File.exists?(f)
File.exist?(f)
end
end
+61 -12
View File
@@ -1,5 +1,6 @@
require "fileutils"
require "open3"
require "set"
module Rscons
# Class to manage a configure operation.
@@ -10,9 +11,11 @@ module Rscons
# @param script [Script]
# Build script.
def initialize(script)
@tested_compilers = {}
@work_dir = "#{Rscons.application.build_dir}/_configure"
FileUtils.mkdir_p(@work_dir)
@log_fh = File.open("#{@work_dir}/config.log", "wb")
@log_file_name = "#{@work_dir}/config.log"
@log_fh = File.open(@log_file_name, "wb")
cache = Cache.instance
cache["failed_commands"] = []
cache["configuration_data"] = {}
@@ -64,7 +67,13 @@ module Rscons
cc = ccc.find do |cc|
test_c_compiler(cc, options)
end
complete(cc ? 0 : 1, options.merge(success_message: cc))
if cc
@tested_compilers["c"] ||= Set.new
@tested_compilers["c"] << cc
end
complete(cc ? 0 : 1, options.merge(
success_message: cc,
fail_message: "not found (checked #{ccc.join(", ")})"))
end
# Check for a working C++ compiler.
@@ -86,7 +95,13 @@ module Rscons
cc = ccc.find do |cc|
test_cxx_compiler(cc, options)
end
complete(cc ? 0 : 1, options.merge(success_message: cc))
if cc
@tested_compilers["cxx"] ||= Set.new
@tested_compilers["cxx"] << cc
end
complete(cc ? 0 : 1, options.merge(
success_message: cc,
fail_message: "not found (checked #{ccc.join(", ")})"))
end
# Check for a working D compiler.
@@ -103,12 +118,18 @@ module Rscons
end
if cdc.empty?
# Default D compiler search array.
cdc = %w[gdc ldc2]
cdc = %w[gdc ldc2 ldc]
end
dc = cdc.find do |dc|
test_d_compiler(dc, options)
end
complete(dc ? 0 : 1, options.merge(success_message: dc))
if dc
@tested_compilers["d"] ||= Set.new
@tested_compilers["d"] << dc
end
complete(dc ? 0 : 1, options.merge(
success_message: dc,
fail_message: "not found (checked #{cdc.join(", ")})"))
end
# Check for a package or configure program output.
@@ -118,7 +139,12 @@ module Rscons
elsif program = options[:program]
Ansi.write($stdout, "Checking '", :cyan, program, :reset, "'... ")
end
program ||= "pkg-config"
unless program
program = "pkg-config"
unless Util.find_executable(program)
raise RsconsError.new("Error: executable '#{program}' not found")
end
end
args = options[:args] || %w[--cflags --libs]
command = [program, *args, package].compact
stdout, _, status = log_and_test_command(command)
@@ -240,17 +266,36 @@ module Rscons
def check_lib(lib, options = {})
check_libpath = [nil] + (options[:check_libpath] || [])
Ansi.write($stdout, "Checking for library '", :cyan, lib, :reset, "'... ")
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
if @tested_compilers["d"]
source_file = "#{@work_dir}/cfgtest.d"
File.open(source_file, "wb") do |fh|
fh.puts <<-EOF
int main() {
return 0;
}
EOF
end
else
source_file = "#{@work_dir}/cfgtest.c"
File.open(source_file, "wb") do |fh|
fh.puts <<-EOF
int main(int argc, char * argv[]) {
return 0;
}
EOF
end
end
ld = "${CC}"
%w[d cxx c].each do |language|
if @tested_compilers[language]
ld = @tested_compilers[language].first
break
end
end
vars = {
"LD" => "${CC}",
"LD" => ld,
"LIBS" => [lib],
"_SOURCES" => "#{@work_dir}/cfgtest.c",
"_SOURCES" => source_file,
"_TARGET" => "#{@work_dir}/cfgtest.exe",
}
status = 1
@@ -375,6 +420,8 @@ module Rscons
# A define to set (in CPPDEFINES) if the requested item is found.
# @option options [String] :success_message
# Message to print on success (default "found").
# @option options [String] :fail_message
# Message to print on failure (default "not found").
def complete(status, options)
success_message = options[:success_message] || "found"
fail_message = options[:fail_message] || "not found"
@@ -398,7 +445,7 @@ module Rscons
options[:on_fail].call
end
if should_fail
raise RsconsError.new("Configuration failed")
raise RsconsError.new("Configuration failed; log file written to #{@log_file_name}")
end
end
end
@@ -482,8 +529,10 @@ module Rscons
env = BasicEnvironment.new
merge = {
"DC" => dc,
"DCCMD" => env["DCCMD"].map {|e| e.sub(/^-o$/, "-of")},
"LDCMD" => env["LDCMD"].map {|e| e.sub(/^-o$/, "-of")},
"DC:-o" => "-of",
"LD:-o" => "-of",
"LIBDIRPREFIX" => "-L-L",
"LIBLINKPREFIX" => "-L-l",
"DDEPGEN" => ["-deps=${_DEPFILE}"],
}
merge["OBJSUFFIX"] = [ldc_objsuffix]
+10 -5
View File
@@ -35,8 +35,9 @@ module Rscons
"CXXFLAGS" => [],
"CXXSUFFIX" => %w[.cc .cpp .cxx .C],
"DC" => "gdc",
"DCCMD" => %w[${DC} -c -o ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${_SOURCES}],
"DCCMD:direct" => %w[${DC} -o ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
"DC:-o" => "-o",
"DCCMD" => %w[${DC} -c ${DC:-o} ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${_SOURCES}],
"DCCMD:direct" => %w[${DC} ${DC:-o} ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
"DDEPGEN" => %w[-MMD -MF ${_DEPFILE}],
"DEPFILESUFFIX" => ".mf",
"DFLAGS" => [],
@@ -46,10 +47,10 @@ module Rscons
"D_IMPORT_PATH" => [],
"INCPREFIX" => "-I",
"LD" => nil,
"LDCMD" => %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
"LD:-o" => "-o",
"LDCMD" => %w[${LD} ${LD:-o} ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
"LDFLAGS" => [],
"LEX" => "flex",
"LEXSUFFIX" => %w[.l .ll],
"LEX_CMD" => %w[${LEX} ${LEX_FLAGS} -o ${_TARGET} ${_SOURCES}],
"LEX_FLAGS" => [],
"LIBDIRPREFIX" => "-L",
@@ -57,6 +58,11 @@ module Rscons
"LIBPATH" => [],
"LIBS" => [],
"LIBSUFFIX" => ".a",
"LLVMAS" => "clang",
"LLVMAS_CMD" => %w[${LLVMAS} -c -o ${_TARGET} ${LLVMAS_FLAGS} ${_SOURCES}],
"LLVMAS_CMD:direct" => %w[${LLVMAS} -o ${_TARGET} ${LLVMAS_FLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}],
"LLVMAS_FLAGS" => [],
"LLVMAS_SUFFIX" => ".ll",
"OBJDUMP" => "objdump",
"OBJSUFFIX" => %w[.o],
"PROGSUFFIX" => on_windows ? ".exe" : "",
@@ -84,7 +90,6 @@ module Rscons
"SIZECMD" => %w[${SIZE} ${SIZEFLAGS} ${_SOURCES}],
"SIZEFLAGS" => [],
"YACC" => "bison",
"YACCSUFFIX" => %w[.y .yy],
"YACC_CMD" => %w[${YACC} ${YACC_FLAGS} -o ${_TARGET} ${_SOURCES}],
"YACC_FLAGS" => %w[-d],
}
+20 -7
View File
@@ -74,15 +74,19 @@ module Rscons
# Create an Environment object.
def initialize(*args, &block)
@id = self.class.get_id
if args.first.is_a?(String)
base_name = args.slice!(0)
else
base_name = "e.#{@id}"
end
variant_keys = (Rscons.application.active_variants || []).map do |variant|
variant[:key]
end.compact
if args.first.is_a?(String)
base_name = args.slice!(0)
@name = [base_name, *variant_keys].join("-")
@build_root = "#{Rscons.application.build_dir}/#{@name}"
else
if variant_keys.size > 0
raise RsconsError.new("Error: an Environment with active variants must be given a name")
end
@build_root = Rscons.application.build_dir
end
options = args.first || {}
unless Cache.instance["configuration_data"]["configured"]
raise "Project must be configured before creating an Environment"
@@ -114,8 +118,8 @@ module Rscons
else
:short
end
@build_root = "#{Rscons.application.build_dir}/#{@name}"
@n_threads = Rscons.application.n_threads
@build_steps = 0
self.class.register(self)
if block
Environment.running_environment = self
@@ -276,7 +280,15 @@ module Rscons
if extra_path = builder_class.extra_path
extra_path = "/#{extra_path}"
end
"#{@build_root}#{extra_path}/#{Util.make_relative_path("#{source_fname}#{suffix}")}".gsub("\\", "/")
source_fname = source_fname.gsub("\\", "/")
if extra_path.nil? && source_fname.start_with?("#{@build_root}/")
# If the source file is in the environment's build directory and no
# builder "extra path" is present, then just place the output file
# next to the source file.
"#{source_fname}#{suffix}"
else
"#{@build_root}/o#{extra_path}/#{Util.make_relative_path("#{source_fname}#{suffix}")}"
end
end
# Build all build targets specified in the Environment.
@@ -359,6 +371,7 @@ module Rscons
@builder_sets << build_builder_set
end
@builder_sets.last << builder
@build_steps += 1
@build_targets[target] = builder
builder
else
+65 -6
View File
@@ -289,27 +289,80 @@ module Rscons
end
# Create or modify a task.
#
# @overload task(name, options = {}, &block)
# @param name [String]
# Task name.
# @param options [Hash]
# Optional task attributes.
# @option options [Boolean] :autoconf
# Whether to automatically configure before running this task
# (default: true).
# @option options [String] :desc
# Description for the task.
# @option options [Array<String>] :depends
# Dependencies of the task.
# @option options [Array<Task::Param>] :params
# Task parameter definitions.
#
# The action block given will be invoked by Rscons when the task
# executes. It will be passed two arguments:
# 1) The Task object.
# 2) A Hash of task parameter names and values.
def task(*args, &block)
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)
#
# @param name [String]
# Variant name.
# @param options [Hash]
# Optional parameters.
# @option options [String] :default
# Whether the variant is enabled by default (default: true).
# @option options [String] :key
# Variant key, used to name an Environment's build directory. If nil,
# this variant will not contribute to the Environment's build directory
# name.
def variant(name, options = {})
Rscons.application.variant(name, options)
end
# Check if a variant is enabled.
def variant_enabled?(*args)
Rscons.application.variant_enabled?(*args)
#
# This can be used, for example, in a configuration block to omit or
# include configuration checks based on which variants have been
# configured.
#
# @param variant_name [String]
# Variant name.
#
# @return [Boolean]
# Whether the requested variant is enabled.
def variant_enabled?(variant_name)
Rscons.application.variant_enabled?(variant_name)
end
# Create a variant group.
#
# @overload variant_group(name, options = {})
# @param name [String]
# Variant group name (optional).
# @param options [Hash]
# Optional variant group parameters.
# @overload variant_group(options = {})
# @param options [Hash]
# Optional variant group parameters.
def variant_group(*args, &block)
Rscons.application.variant_group(*args, &block)
end
# Iterate through variants.
# Iterate through enabled variants.
#
# The given block is called for each combination of enabled variants
# across the defined variant groups.
def with_variants(&block)
Rscons.application.enable_variants
Rscons.application.with_variants(&block)
@@ -349,11 +402,17 @@ module Rscons
# Top-level DSL available to the Rsconscript.
class TopLevelDsl < GlobalDsl
# Set the project name.
#
# @param project_name [String]
# Project name.
def project_name(project_name)
@script.project_name = project_name
end
# Whether to automatically configure (default true).
# Set whether to automatically configure (default true).
#
# @param autoconf [Boolean]
# Whether to automatically configure.
def autoconf(autoconf)
@script.autoconf = autoconf
end
+1 -1
View File
@@ -1,4 +1,4 @@
module Rscons
# Project version.
VERSION = "3.0.2"
VERSION = "3.2.0"
end
+2 -2
View File
@@ -22,7 +22,7 @@ combine_files = lambda do |file|
require_name = $1
if require_name =~ %r{^#{PROG_NAME}(?:/.*)?$}
path = "#{LIB_DIR}/#{require_name}.rb"
if File.exists?(path)
if File.exist?(path)
unless files_processed[path]
files_processed[path] = true
combine_files[path]
@@ -83,7 +83,7 @@ File.open("#{DIST}/#{PROG_NAME}", "wb", 0755) do |fh|
#{license}
script = File.join(File.dirname(__FILE__), ".rscons-#{VERSION}-#{hash}.rb")
unless File.exists?(script)
unless File.exist?(script)
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
require "zlib"
require "base64"
+1 -1
View File
@@ -99,7 +99,7 @@ class Generator
end
template = File.read("rb/assets/user_guide.html.erb")
erb = ERB.new(template, nil, "<>")
erb = ERB.new(template, trim_mode: "<>")
if multi_page
@pages.each_with_index do |page, page_index|
+238 -178
View File
@@ -7,16 +7,16 @@ describe Rscons do
def rm_rf(dir)
FileUtils.rm_rf(dir)
if File.exists?(dir)
if File.exist?(dir)
sleep 0.2
FileUtils.rm_rf(dir)
if File.exists?(dir)
if File.exist?(dir)
sleep 0.5
FileUtils.rm_rf(dir)
if File.exists?(dir)
if File.exist?(dir)
sleep 1.0
FileUtils.rm_rf(dir)
if File.exists?(dir)
if File.exist?(dir)
raise "Could not remove #{dir}"
end
end
@@ -43,7 +43,11 @@ describe Rscons do
Dir.chdir(@owd)
if example.exception
@statics[:keep_test_run_dir] = true
puts "Leaving #{@build_test_run_dir} for inspection due to test failure"
message = "Leaving #{@build_test_run_dir} for inspection due to test failure"
if example.exception.backtrace.find {|e| e =~ %r{^(.*/#{File.basename(__FILE__)}:\d+)}}
message += " (#{$1})"
end
puts "\n#{message}"
else
rm_rf(@build_test_run_dir)
end
@@ -191,7 +195,7 @@ EOF
test_dir('simple')
result = run_rscons
expect(result.stderr).to eq ""
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
expect(File.exist?('build/o/simple.c.o')).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
end
@@ -199,7 +203,7 @@ EOF
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(File.exist?("build/o/simple.c.o")).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
end
@@ -208,7 +212,7 @@ EOF
result = run_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
expect(File.exist?("b/o/simple.c.o")).to be_truthy
end
it "uses the build directory specified by an environment variable" do
@@ -217,14 +221,14 @@ EOF
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
expect(File.exist?("b2/o/simple.c.o")).to be_truthy
end
it "allows specifying a Builder object as the source to another build target" do
test_dir("simple")
result = run_rscons(args: %w[-f builder_as_source.rb])
expect(result.stderr).to eq ""
expect(File.exists?("simple.o")).to be_truthy
expect(File.exist?("simple.o")).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
end
@@ -233,8 +237,8 @@ EOF
result = run_rscons(args: %w[-f command.rb])
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%r{gcc -c -o build/e.1/simple.c.o -MMD -MF build/e.1/simple.c.o.mf simple.c},
%r{gcc -o simple.exe build/e.1/simple.c.o},
%r{gcc -c -o build/o/simple.c.o -MMD -MF build/o/simple.c.o.mf simple.c},
%r{gcc -o simple.exe build/o/simple.c.o},
])
end
@@ -252,7 +256,7 @@ EOF
test_dir('header')
result = run_rscons
expect(result.stderr).to eq ""
expect(File.exists?('build/e.1/header.c.o')).to be_truthy
expect(File.exist?('build/o/header.c.o')).to be_truthy
expect(nr(`./header.exe`)).to eq "The value is 2\n"
end
@@ -302,13 +306,13 @@ EOF
result = run_rscons(args: %w[-f command.rb])
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%r{gcc -c -o build/e.1/simple.c.o -MMD -MF build/e.1/simple.c.o.mf simple.c},
%r{gcc -o simple.exe build/e.1/simple.c.o},
%r{gcc -c -o build/o/simple.c.o -MMD -MF build/o/simple.c.o.mf simple.c},
%r{gcc -o simple.exe build/o/simple.c.o},
])
result = run_rscons(args: %w[-f link_flag_change.rb])
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%r{gcc -o simple.exe build/e.1/simple.c.o -Llibdir},
%r{gcc -o simple.exe build/o/simple.c.o -Llibdir},
])
end
@@ -338,9 +342,9 @@ EOF
result = run_rscons(args: %w[-f carat.rb -b bld])
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%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 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 bld/program.exe bld/e.1/one.o bld/e.1/bld/two.c.o},
%r{gcc -c -o bld/one.o -MMD -MF bld/one.o.mf -Isrc -Isrc/one -Isrc/two bld/one.c},
%r{gcc -c -o bld/two.c.o -MMD -MF bld/two.c.o.mf -Isrc -Isrc/one -Isrc/two bld/two.c},
%r{gcc -o bld/program.exe bld/one.o bld/two.c.o},
])
end
@@ -348,7 +352,7 @@ EOF
test_dir('json_to_yaml')
result = run_rscons
expect(result.stderr).to eq ""
expect(File.exists?('foo.yml')).to be_truthy
expect(File.exist?('foo.yml')).to be_truthy
expect(nr(IO.read('foo.yml'))).to eq("---\nkey: value\n")
end
@@ -364,33 +368,33 @@ EOF
result = run_rscons
expect(result.stderr).to eq ""
expect(`./simple.exe`).to match /This is a simple C program/
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
expect(File.exist?('build/o/simple.c.o')).to be_truthy
result = run_rscons(args: %w[clean])
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(File.exist?('build/o/simple.c.o')).to be_falsey
expect(File.exist?('build/o')).to be_falsey
expect(File.exist?('simple.exe')).to be_falsey
expect(File.exist?('simple.c')).to be_truthy
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
expect(File.exist?("build/o/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
expect(File.exist?("build/o/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(File.exist?('build/o/simple.c.o')).to be_falsey
expect(File.exist?('build/o')).to be_falsey
expect(File.exist?('simple.exe')).to be_falsey
expect(File.exist?('simple.c')).to be_truthy
expect(result.stdout).to eq ""
end
@@ -399,11 +403,11 @@ EOF
result = run_rscons
expect(result.stderr).to eq ""
expect(`./simple.exe`).to match /This is a simple C program/
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
File.open('build/e.1/dum', 'w') { |fh| fh.puts "dum" }
expect(File.exist?('build/o/simple.c.o')).to be_truthy
File.open('build/o/dum', 'w') { |fh| fh.puts "dum" }
result = run_rscons(args: %w[clean])
expect(File.exists?('build/e.1')).to be_truthy
expect(File.exists?('build/e.1/dum')).to be_truthy
expect(File.exist?('build/o')).to be_truthy
expect(File.exist?('build/o/dum')).to be_truthy
end
it "removes built files but not installed files" do
@@ -415,13 +419,13 @@ EOF
result = run_rscons(args: %w[-f install.rb install])
expect(result.stderr).to eq ""
expect(File.exists?("#{prefix}/bin/program.exe")).to be_truthy
expect(File.exists?("build/e.1/src/one/one.c.o")).to be_truthy
expect(File.exist?("#{prefix}/bin/program.exe")).to be_truthy
expect(File.exist?("build/o/src/one/one.c.o")).to be_truthy
result = run_rscons(args: %w[-f install.rb clean])
expect(result.stderr).to eq ""
expect(File.exists?("#{prefix}/bin/program.exe")).to be_truthy
expect(File.exists?("build/e.1/src/one/one.c.o")).to be_falsey
expect(File.exist?("#{prefix}/bin/program.exe")).to be_truthy
expect(File.exist?("build/o/src/one/one.c.o")).to be_falsey
end
end
@@ -437,8 +441,8 @@ EOF
result = run_rscons(args: %w[-f install.rb clean])
expect(result.stderr).to eq ""
expect(File.exists?("#{prefix}/bin/program.exe")).to be_truthy
expect(File.exists?("build/e.1/src/one/one.c.o")).to be_falsey
expect(File.exist?("#{prefix}/bin/program.exe")).to be_truthy
expect(File.exist?("build/o/src/one/one.c.o")).to be_falsey
result = run_rscons(args: %w[-f install.rb -v uninstall])
expect(result.stderr).to eq ""
@@ -456,7 +460,7 @@ EOF
%r{Compiling program.c},
%r{Linking program.exe},
])
expect(File.exists?('inc.h')).to be_truthy
expect(File.exist?('inc.h')).to be_truthy
expect(nr(`./program.exe`)).to eq "The value is 5678\n"
end
@@ -471,8 +475,8 @@ EOF
%r{Compiling inc.c},
%r{Linking program.exe},
])
expect(File.exists?("inc.c")).to be_truthy
expect(File.exists?("inc.h")).to be_truthy
expect(File.exist?("inc.c")).to be_truthy
expect(File.exist?("inc.h")).to be_truthy
expect(nr(`./program.exe`)).to eq "The value is 42\n"
File.open("inc.c", "w") {|fh| fh.puts "int THE_VALUE = 33;"}
@@ -502,7 +506,7 @@ EOF
expect(result.stderr).to eq ""
expect(result.status).to eq 0
verify_lines(lines(result.stdout), [%r{MyBuilder foo}])
expect(File.exists?("foo")).to be_truthy
expect(File.exist?("foo")).to be_truthy
end
it 'supports a Builder waiting for another Builder' do
@@ -511,8 +515,8 @@ EOF
expect(result.stderr).to eq ""
expect(result.status).to eq 0
verify_lines(lines(result.stdout), [%r{MyObject simple.o}])
expect(File.exists?("simple.o")).to be_truthy
expect(File.exists?("simple.exe")).to be_truthy
expect(File.exist?("simple.o")).to be_truthy
expect(File.exist?("simple.exe")).to be_truthy
end
it 'allows cloning Environment objects' do
@@ -520,10 +524,10 @@ EOF
result = run_rscons
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%r{gcc -c -o build/e.1/src/program.c.o -MMD -MF build/e.1/src/program.c.o.mf '-DSTRING="Debug Version"' -O2 src/program.c},
%r{gcc -o program-debug.exe build/e.1/src/program.c.o},
%r{gcc -c -o build/e.2/src/program.c.o -MMD -MF build/e.2/src/program.c.o.mf '-DSTRING="Release Version"' -O2 src/program.c},
%r{gcc -o program-release.exe build/e.2/src/program.c.o},
%r{gcc -c -o build/dbg/o/src/program.c.o -MMD -MF build/dbg/o/src/program.c.o.mf '-DSTRING="Debug Version"' -O2 src/program.c},
%r{gcc -o program-debug.exe build/dbg/o/src/program.c.o},
%r{gcc -c -o build/rls/o/src/program.c.o -MMD -MF build/rls/o/src/program.c.o.mf '-DSTRING="Release Version"' -O2 src/program.c},
%r{gcc -o program-release.exe build/rls/o/src/program.c.o},
])
end
@@ -532,12 +536,12 @@ EOF
result = run_rscons(args: %w[-f clone_all.rb])
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%r{gcc -c -o build/e.1/src/program.c.o -MMD -MF build/e.1/src/program.c.o.mf -DSTRING="Hello" -O2 src/program.c},
%r{post build/e.1/src/program.c.o},
%r{gcc -o program.exe build/e.1/src/program.c.o},
%r{gcc -c -o build/e1/o/src/program.c.o -MMD -MF build/e1/o/src/program.c.o.mf -DSTRING="Hello" -O2 src/program.c},
%r{post build/e1/o/src/program.c.o},
%r{gcc -o program.exe build/e1/o/src/program.c.o},
%r{post program.exe},
%r{post build/e.2/src/program.c.o},
%r{gcc -o program2.exe build/e.2/src/program.c.o},
%r{post build/e2/o/src/program.c.o},
%r{gcc -o program2.exe build/e2/o/src/program.c.o},
%r{post program2.exe},
])
end
@@ -546,7 +550,7 @@ EOF
test_dir('simple_cc')
result = run_rscons
expect(result.stderr).to eq ""
expect(File.exists?('build/e.1/simple.cc.o')).to be_truthy
expect(File.exist?('build/o/simple.cc.o')).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C++ program\n"
end
@@ -554,7 +558,7 @@ EOF
test_dir("simple_cc")
result = run_rscons(args: %w[-f link_objects.rb])
expect(result.stderr).to eq ""
expect(File.exists?("simple.o")).to be_truthy
expect(File.exist?("simple.o")).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C++ program\n"
end
@@ -563,11 +567,11 @@ EOF
result = run_rscons
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%r{gcc -c -o one.o -MMD -MF build/e.1/one.o.mf -DONE one.c},
%r{gcc -c -o build/e.1/two.c.o -MMD -MF build/e.1/two.c.o.mf two.c},
%r{gcc -o two_sources.exe one.o build/e.1/two.c.o},
%r{gcc -c -o one.o -MMD -MF build/o/one.o.mf -DONE one.c},
%r{gcc -c -o build/o/two.c.o -MMD -MF build/o/two.c.o.mf two.c},
%r{gcc -o two_sources.exe one.o build/o/two.c.o},
])
expect(File.exists?("two_sources.exe")).to be_truthy
expect(File.exist?("two_sources.exe")).to be_truthy
expect(nr(`./two_sources.exe`)).to eq "This is a C program with two sources.\n"
end
@@ -576,13 +580,13 @@ EOF
result = run_rscons
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%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/three.c.o -MMD -MF build/e.1/three.c.o.mf -Dmake_lib three.c},
%r{ar rcs libmylib.a build/e.1/two.c.o 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},
%r{gcc -c -o build/o/two.c.o -MMD -MF build/o/two.c.o.mf -Dmake_lib two.c},
%r{gcc -c -o build/o/three.c.o -MMD -MF build/o/three.c.o.mf -Dmake_lib three.c},
%r{ar rcs libmylib.a build/o/two.c.o build/o/three.c.o},
%r{gcc -c -o build/o/one.c.o -MMD -MF build/o/one.c.o.mf one.c},
%r{gcc -o library.exe build/o/one.c.o -L. -lmylib},
])
expect(File.exists?("library.exe")).to be_truthy
expect(File.exist?("library.exe")).to be_truthy
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}
@@ -593,9 +597,9 @@ EOF
result = run_rscons(args: %w[-f build_hooks.rb])
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%r{gcc -c -o build/e.1/src/one/one.c.o -MMD -MF build/e.1/src/one/one.c.o.mf -Isrc/one -Isrc/two -O1 src/one/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/one -Isrc/two -O2 src/two/two.c},
%r{gcc -o build_hook.exe build/e.1/src/one/one.c.o build/e.1/src/two/two.c.o},
%r{gcc -c -o build/o/src/one/one.c.o -MMD -MF build/o/src/one/one.c.o.mf -Isrc/one -Isrc/two -O1 src/one/one.c},
%r{gcc -c -o build/o/src/two/two.c.o -MMD -MF build/o/src/two/two.c.o.mf -Isrc/one -Isrc/two -O2 src/two/two.c},
%r{gcc -o build_hook.exe build/o/src/one/one.c.o build/o/src/two/two.c.o},
])
expect(nr(`./build_hook.exe`)).to eq "Hello from two()\n"
end
@@ -605,11 +609,11 @@ EOF
result = run_rscons(args: %w[-f build_hooks_override_vars.rb])
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%r{gcc -c -o one.o -MMD -MF build/e.1/one.o.mf -Isrc -Isrc/one -Isrc/two -O1 src/two/two.c},
%r{gcc -c -o two.o -MMD -MF build/e.1/two.o.mf -Isrc -Isrc/one -Isrc/two -O2 src/two/two.c},
%r{gcc -c -o one.o -MMD -MF build/o/one.o.mf -Isrc -Isrc/one -Isrc/two -O1 src/two/two.c},
%r{gcc -c -o two.o -MMD -MF build/o/two.o.mf -Isrc -Isrc/one -Isrc/two -O2 src/two/two.c},
])
expect(File.exists?('one.o')).to be_truthy
expect(File.exists?('two.o')).to be_truthy
expect(File.exist?('one.o')).to be_truthy
expect(File.exist?('two.o')).to be_truthy
end
it 'rebuilds when user-specified dependencies change' do
@@ -622,7 +626,7 @@ EOF
%r{Compiling simple.c},
%r{Linking simple.exe},
])
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
expect(File.exist?('build/o/simple.c.o')).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
File.open("program.ld", "w") {|fh| fh.puts("2")}
@@ -667,9 +671,9 @@ EOF
result = run_rscons
expect(result.stderr).to eq ""
slines = lines(result.stdout)
verify_lines(slines, [%r{gdc -c -o build/e.1/main.d.o -MMD -MF build/e.1/main.d.o.mf main.d}])
verify_lines(slines, [%r{gdc -c -o build/e.1/mod.d.o -MMD -MF build/e.1/mod.d.o.mf mod.d}])
verify_lines(slines, [%r{gdc -o hello-d.exe build/e.1/main.d.o build/e.1/mod.d.o}])
verify_lines(slines, [%r{gdc -c -o build/o/main.d.o -MMD -MF build/o/main.d.o.mf main.d}])
verify_lines(slines, [%r{gdc -c -o build/o/mod.d.o -MMD -MF build/o/mod.d.o.mf mod.d}])
verify_lines(slines, [%r{gdc -o hello-d.exe build/o/main.d.o build/o/mod.d.o}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
end
end
@@ -679,9 +683,9 @@ EOF
result = run_rscons(args: %w[-f build-ldc2.rb])
expect(result.stderr).to eq ""
slines = lines(result.stdout)
verify_lines(slines, [%r{ldc2 -c -of build/e.1/main.d.o(bj)? -deps=build/e.1/main.d.o(bj)?.mf main.d}])
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o(bj)?.mf mod.d}])
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/e.1/main.d.o(bj)? build/e.1/mod.d.o(bj)?}])
verify_lines(slines, [%r{ldc2 -c -of build/o/main.d.o(bj)? -deps=build/o/main.d.o(bj)?.mf main.d}])
verify_lines(slines, [%r{ldc2 -c -of build/o/mod.d.o(bj)? -deps=build/o/mod.d.o(bj)?.mf mod.d}])
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/o/main.d.o(bj)? build/o/mod.d.o(bj)?}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
end
@@ -690,9 +694,9 @@ EOF
result = run_rscons(args: %w[-f build-ldc2.rb])
expect(result.stderr).to eq ""
slines = lines(result.stdout)
verify_lines(slines, [%r{ldc2 -c -of build/e.1/main.d.o(bj)? -deps=build/e.1/main.d.o(bj)?.mf main.d}])
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o(bj)?.mf mod.d}])
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/e.1/main.d.o(bj)? build/e.1/mod.d.o(bj)?}])
verify_lines(slines, [%r{ldc2 -c -of build/o/main.d.o(bj)? -deps=build/o/main.d.o(bj)?.mf main.d}])
verify_lines(slines, [%r{ldc2 -c -of build/o/mod.d.o(bj)? -deps=build/o/mod.d.o(bj)?.mf mod.d}])
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/o/main.d.o(bj)? build/o/mod.d.o(bj)?}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
contents = File.read("mod.d", mode: "rb").sub("42", "33")
File.open("mod.d", "wb") do |fh|
@@ -701,9 +705,9 @@ EOF
result = run_rscons(args: %w[-f build-ldc2.rb])
expect(result.stderr).to eq ""
slines = lines(result.stdout)
verify_lines(slines, [%r{ldc2 -c -of build/e.1/main.d.o(bj)? -deps=build/e.1/main.d.o(bj)?.mf main.d}])
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o(bj)?.mf mod.d}])
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/e.1/main.d.o(bj)? build/e.1/mod.d.o(bj)?}])
verify_lines(slines, [%r{ldc2 -c -of build/o/main.d.o(bj)? -deps=build/o/main.d.o(bj)?.mf main.d}])
verify_lines(slines, [%r{ldc2 -c -of build/o/mod.d.o(bj)? -deps=build/o/mod.d.o(bj)?.mf mod.d}])
verify_lines(slines, [%r{ldc2 -of hello-d.exe build/o/main.d.o(bj)? build/o/mod.d.o(bj)?}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 33!"
end
@@ -712,8 +716,8 @@ EOF
test_dir("d")
result = run_rscons(args: %w[-f link_objects.rb])
expect(result.stderr).to eq ""
expect(File.exists?("main.o")).to be_truthy
expect(File.exists?("mod.o")).to be_truthy
expect(File.exist?("main.o")).to be_truthy
expect(File.exist?("mod.o")).to be_truthy
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
end
@@ -722,18 +726,18 @@ EOF
result = run_rscons
expect(result.stderr).to eq ""
slines = lines(result.stdout)
verify_lines(slines, [%r{gdc -c -o build/e.1/main.d.o -MMD -MF build/e.1/main.d.o.mf main.d}])
verify_lines(slines, [%r{gdc -c -o build/e.1/mod.d.o -MMD -MF build/e.1/mod.d.o.mf mod.d}])
verify_lines(slines, [%r{gdc -o hello-d.exe build/e.1/main.d.o build/e.1/mod.d.o}])
verify_lines(slines, [%r{gdc -c -o build/o/main.d.o -MMD -MF build/o/main.d.o.mf main.d}])
verify_lines(slines, [%r{gdc -c -o build/o/mod.d.o -MMD -MF build/o/mod.d.o.mf mod.d}])
verify_lines(slines, [%r{gdc -o hello-d.exe build/o/main.d.o build/o/mod.d.o}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
fcontents = File.read("mod.d", mode: "rb").sub("42", "33")
File.open("mod.d", "wb") {|fh| fh.write(fcontents)}
result = run_rscons
expect(result.stderr).to eq ""
slines = lines(result.stdout)
verify_lines(slines, [%r{gdc -c -o build/e.1/main.d.o -MMD -MF build/e.1/main.d.o.mf main.d}])
verify_lines(slines, [%r{gdc -c -o build/e.1/mod.d.o -MMD -MF build/e.1/mod.d.o.mf mod.d}])
verify_lines(slines, [%r{gdc -o hello-d.exe build/e.1/main.d.o build/e.1/mod.d.o}])
verify_lines(slines, [%r{gdc -c -o build/o/main.d.o -MMD -MF build/o/main.d.o.mf main.d}])
verify_lines(slines, [%r{gdc -c -o build/o/mod.d.o -MMD -MF build/o/mod.d.o.mf mod.d}])
verify_lines(slines, [%r{gdc -o hello-d.exe build/o/main.d.o build/o/mod.d.o}])
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 33!"
end
@@ -756,7 +760,7 @@ EOF
result = run_rscons(args: %w[-f disassemble.rb])
expect(result.stderr).to eq ""
expect(File.exists?("simple.txt")).to be_truthy
expect(File.exist?("simple.txt")).to be_truthy
expect(File.read("simple.txt")).to match /Disassembly of section .text:/
result = run_rscons(args: %w[-f disassemble.rb])
@@ -794,7 +798,7 @@ EOF
%r{Compiling program.c},
%r{Linking program.exe},
])
expect(File.exists?('inc.h')).to be_truthy
expect(File.exist?('inc.h')).to be_truthy
expect(nr(`./program.exe`)).to eq "The value is 678\n"
end
@@ -809,8 +813,8 @@ EOF
test_dir("simple")
result = run_rscons(args: %w[-f register_target_in_build_hook.rb])
expect(result.stderr).to eq ""
expect(File.exists?("build/e.1/simple.c.o")).to be_truthy
expect(File.exists?("build/e.1/simple.c.o.txt")).to be_truthy
expect(File.exist?("build/o/simple.c.o")).to be_truthy
expect(File.exist?("build/o/simple.c.o.txt")).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
end
@@ -819,8 +823,8 @@ EOF
File.open("other.cccc", "w") {|fh| fh.puts}
result = run_rscons(args: %w[-f cxxsuffix.rb])
expect(result.stderr).to eq ""
expect(File.exists?("build/e.1/simple.cc.o")).to be_truthy
expect(File.exists?("build/e.1/other.cccc.o")).to be_truthy
expect(File.exist?("build/o/simple.cc.o")).to be_truthy
expect(File.exist?("build/o/other.cccc.o")).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C++ program\n"
end
@@ -829,8 +833,8 @@ EOF
FileUtils.mv("src/one/one.c", "src/one/one.yargh")
result = run_rscons(args: %w[-f csuffix.rb])
expect(result.stderr).to eq ""
expect(File.exists?("build/e.1/src/one/one.yargh.o")).to be_truthy
expect(File.exists?("build/e.1/src/two/two.c.o")).to be_truthy
expect(File.exist?("build/o/src/one/one.yargh.o")).to be_truthy
expect(File.exist?("build/o/src/two/two.c.o")).to be_truthy
expect(nr(`./program.exe`)).to eq "Hello from two()\n"
end
@@ -838,9 +842,9 @@ EOF
test_dir("two_sources")
result = run_rscons(args: %w[-f objsuffix.rb])
expect(result.stderr).to eq ""
expect(File.exists?("two_sources.exe")).to be_truthy
expect(File.exists?("one.oooo")).to be_truthy
expect(File.exists?("two.ooo")).to be_truthy
expect(File.exist?("two_sources.exe")).to be_truthy
expect(File.exist?("one.oooo")).to be_truthy
expect(File.exist?("two.ooo")).to be_truthy
expect(nr(`./two_sources.exe`)).to eq "This is a C program with two sources.\n"
end
@@ -848,7 +852,7 @@ EOF
test_dir("two_sources")
result = run_rscons(args: %w[-f libsuffix.rb])
expect(result.stderr).to eq ""
expect(File.exists?("two_sources.exe")).to be_truthy
expect(File.exist?("two_sources.exe")).to be_truthy
expect(nr(`./two_sources.exe`)).to eq "This is a C program with two sources.\n"
end
@@ -863,7 +867,7 @@ EOF
%r{Assembling two.sss},
%r{Linking two_sources.exe},
])
expect(File.exists?("two_sources.exe")).to be_truthy
expect(File.exist?("two_sources.exe")).to be_truthy
expect(nr(`./two_sources.exe`)).to eq "This is a C program with two sources.\n"
end
@@ -902,7 +906,7 @@ EOF
test_dir("simple")
result = run_rscons(args: %w[-f cvar_array.rb])
expect(result.stderr).to eq ""
expect(File.exists?("build/e.1/simple.c.o")).to be_truthy
expect(File.exist?("build/o/simple.c.o")).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
end
@@ -910,7 +914,7 @@ EOF
test_dir("typical")
result = run_rscons(args: %w[-f multiple_targets_same_name.rb])
expect(result.stderr).to eq ""
expect(File.exists?("one.o")).to be_truthy
expect(File.exist?("one.o")).to be_truthy
verify_lines(lines(result.stdout), [
%r{Compiling src/one/one.c},
%r{Compiling src/two/two.c},
@@ -921,8 +925,8 @@ EOF
test_dir("typical")
result = run_rscons(args: %w[-f post_build_hook_expansion.rb])
expect(result.stderr).to eq ""
expect(File.exists?("one.o")).to be_truthy
expect(File.exists?("two.o")).to be_truthy
expect(File.exist?("one.o")).to be_truthy
expect(File.exist?("two.o")).to be_truthy
verify_lines(lines(result.stdout), [
%r{Compiling src/one/one.c},
%r{Compiling src/two/two.c},
@@ -936,8 +940,8 @@ EOF
end
result = run_rscons(args: %w[-f cache_successful_builds_when_one_fails.rb -j1])
expect(result.stderr).to match /FOO/
expect(File.exists?("simple.o")).to be_truthy
expect(File.exists?("two.o")).to be_falsey
expect(File.exist?("simple.o")).to be_truthy
expect(File.exist?("two.o")).to be_falsey
File.open("two.c", "w") {|fh|}
result = run_rscons(args: %w[-f cache_successful_builds_when_one_fails.rb -j1])
@@ -982,10 +986,18 @@ EOF
result = run_rscons(args: %w[-f absolute_source_path.rb])
expect(result.stderr).to eq ""
slines = lines(result.stdout)
verify_lines(slines, [%r{build/e.1/.*/abs\.c.o$}])
verify_lines(slines, [%r{build/o/.*/abs\.c.o$}])
verify_lines(slines, [%r{\babs.exe\b}])
end
it "creates object files next to the source file for source files in the build root" do
test_dir "simple"
result = run_rscons(args: %w[-f build_root_source_path.rb])
expect(result.stderr).to eq ""
expect(File.exist?("build/e/o/build/e/src/foo.c.o")).to be_falsey
expect(File.exist?("build/e/src/foo.c.o")).to be_truthy
end
it "creates shared libraries" do
test_dir("shared_library")
@@ -994,10 +1006,10 @@ EOF
slines = lines(result.stdout)
if RUBY_PLATFORM =~ /mingw|msys/
verify_lines(slines, [%r{Linking mine.dll}])
expect(File.exists?("mine.dll")).to be_truthy
expect(File.exist?("mine.dll")).to be_truthy
else
verify_lines(slines, [%r{Linking libmine.so}])
expect(File.exists?("libmine.so")).to be_truthy
expect(File.exist?("libmine.so")).to be_truthy
end
result = run_rscons
@@ -1014,7 +1026,7 @@ EOF
result = run_rscons(args: %w[-f shared_library_as.rb])
expect(result.stderr).to eq ""
expect(File.exists?("file.S")).to be_truthy
expect(File.exist?("file.S")).to be_truthy
end
it "creates shared libraries using C++" do
@@ -1115,7 +1127,7 @@ EOF
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
expect(File.exist?("build/typical/o/src/one/one.c.o")).to be_truthy
end
it "names Environment during clone" do
@@ -1123,8 +1135,8 @@ EOF
result = run_rscons(args: %w[-f 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
expect(File.exist?("build/typical/o/src/one/one.c.o")).to be_truthy
expect(Dir.exist?("build/o")).to be_falsey
end
it "allows looking up environments by name" do
@@ -1132,7 +1144,7 @@ EOF
result = run_rscons(args: %w[-f clone_with_lookup.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(File.exist?("build/typical/o/src/one/one.c.o")).to be_truthy
expect(Dir.exist?("build/first")).to be_falsey
end
@@ -1159,28 +1171,21 @@ EOF
end
end
context "CFile builder" do
it "builds a .c file using flex and bison" do
test_dir("cfile")
context "Lex and Yacc builders" do
it "builds C files using flex and bison" do
test_dir("lex_yacc")
result = run_rscons
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%r{Generating lexer from lexer.l => lexer.c},
%r{Generating parser from parser.y => parser.c},
%r{Generating lexer source from lexer.l => lexer.c},
%r{Generating parser source from parser.y => parser.c},
])
result = run_rscons
expect(result.stderr).to eq ""
expect(result.stdout).to eq ""
end
it "raises an error when an unknown source file is specified" do
test_dir("cfile")
result = run_rscons(args: %w[-f error_unknown_extension.rb])
expect(result.stderr).to match /Unknown source file .foo.bar. for CFile builder/
expect(result.status).to_not eq 0
end
end
context "Command builder" do
@@ -1248,7 +1253,7 @@ EOF
expect(result.stderr).to eq ""
expect(result.stdout).to eq ""
expect(File.exists?("inst.exe")).to be_truthy
expect(File.exist?("inst.exe")).to be_truthy
expect(File.read("inst.exe", mode: "rb")).to eq(File.read("copy.rb", mode: "rb"))
FileUtils.rm("inst.exe")
@@ -1268,9 +1273,9 @@ EOF
expect(result.stderr).to eq ""
expect(result.stdout).to eq ""
expect(Dir.exists?("dest")).to be_truthy
expect(File.exists?("dest/copy.rb")).to be_truthy
expect(File.exists?("dest/copy_multiple.rb")).to be_truthy
expect(Dir.exist?("dest")).to be_truthy
expect(File.exist?("dest/copy.rb")).to be_truthy
expect(File.exist?("dest/copy_multiple.rb")).to be_truthy
FileUtils.rm_rf("dest")
result = run_rscons(args: %w[-f copy_multiple.rb])
@@ -1284,7 +1289,7 @@ EOF
result = run_rscons(args: %w[-f copy_directory.rb])
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [%r{Copy copy_directory.rb => copy}])
expect(File.exists?("copy/copy_directory.rb")).to be_truthy
expect(File.exist?("copy/copy_directory.rb")).to be_truthy
expect(File.read("copy/copy_directory.rb", mode: "rb")).to eq(File.read("copy_directory.rb", mode: "rb"))
result = run_rscons(args: %w[-f copy_directory.rb])
@@ -1298,7 +1303,7 @@ EOF
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [%r{Copy src => noexist/src}])
%w[src/one/one.c src/two/two.c src/two/two.h].each do |f|
expect(File.exists?("noexist/#{f}")).to be_truthy
expect(File.exist?("noexist/#{f}")).to be_truthy
expect(File.read("noexist/#{f}", mode: "rb")).to eq(File.read(f, mode: "rb"))
end
end
@@ -1309,7 +1314,7 @@ EOF
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [%r{Copy src => exist/src}])
%w[src/one/one.c src/two/two.c src/two/two.h].each do |f|
expect(File.exists?("exist/#{f}")).to be_truthy
expect(File.exist?("exist/#{f}")).to be_truthy
expect(File.read("exist/#{f}", mode: "rb")).to eq(File.read(f, mode: "rb"))
end
end
@@ -1366,10 +1371,10 @@ EOF
it "forces a build when the target file does not exist and is not in the cache" do
test_dir("simple")
expect(File.exists?("simple.exe")).to be_falsey
expect(File.exist?("simple.exe")).to be_falsey
result = run_rscons
expect(result.stderr).to eq ""
expect(File.exists?("simple.exe")).to be_truthy
expect(File.exist?("simple.exe")).to be_truthy
end
it "forces a build when the target file does exist but is not in the cache" do
@@ -1379,7 +1384,7 @@ EOF
end
result = run_rscons
expect(result.stderr).to eq ""
expect(File.exists?("simple.exe")).to be_truthy
expect(File.exist?("simple.exe")).to be_truthy
expect(File.read("simple.exe", mode: "rb")).to_not eq "hi"
end
@@ -1393,7 +1398,7 @@ EOF
test_dir("simple")
result = run_rscons
expect(result.stderr).to eq ""
expect(File.exists?("simple.exe")).to be_truthy
expect(File.exist?("simple.exe")).to be_truthy
expect(File.read("simple.exe", mode: "rb")).to_not eq "hi"
end
@@ -1552,7 +1557,7 @@ EOF
expect(result.stdout).to match /Compiling simple\.c/
expect(File.exist?("simple.o")).to be_truthy
expect(File.exist?("simple.o.mf")).to be_falsey
expect(File.exist?("build/e.1/simple.o.mf")).to be_truthy
expect(File.exist?("build/o/simple.o.mf")).to be_truthy
end
context "debugging" do
@@ -1653,7 +1658,7 @@ EOF
result = run_rscons(args: %w[-f override_depfilesuffix.rb])
expect(result.stderr).to eq ""
verify_lines(lines(result.stdout), [
%r{gcc -c -o simple.o -MMD -MF build/e.1/simple.o.deppy simple.c},
%r{gcc -c -o simple.o -MMD -MF build/o/simple.o.deppy simple.c},
])
end
@@ -1677,14 +1682,14 @@ EOF
test_dir("library")
result = run_rscons(args: %w[-f override_arcmd.rb])
expect(result.stderr).to eq ""
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}])
verify_lines(lines(result.stdout), [%r{ar rc lib.a build/o/one.c.o build/o/three.c.o build/o/two.c.o}])
end
it "allows passing object files as sources" do
test_dir("library")
result = run_rscons(args: %w[-f library_from_object.rb])
expect(result.stderr).to eq ""
expect(File.exists?("two.o")).to be_truthy
expect(File.exist?("two.o")).to be_truthy
verify_lines(lines(result.stdout), [%r{Building static library archive lib.a}])
end
end
@@ -1707,7 +1712,7 @@ EOF
test_dir "shared_library"
result = run_rscons(args: %w[-f shared_library_from_object.rb])
expect(result.stderr).to eq ""
expect(File.exists?("one.c.o"))
expect(File.exist?("one.c.o"))
end
end
@@ -1752,14 +1757,14 @@ EOF
test_dir("custom_builder")
result = run_rscons(args: %w[-f produces.rb -j 4])
expect(result.stderr).to eq ""
expect(File.exists?("copy_inc.h")).to be_truthy
expect(File.exist?("copy_inc.h")).to be_truthy
end
it "allows the user to specify side-effect files produced by another builder with Environment#produces" do
test_dir("custom_builder")
result = run_rscons(args: %w[-f produces_env.rb -j 4])
expect(result.stderr).to eq ""
expect(File.exists?("copy_inc.h")).to be_truthy
expect(File.exist?("copy_inc.h")).to be_truthy
end
end
@@ -1933,9 +1938,9 @@ EOF
create_exe "gcc", "exit 1"
create_exe "clang", "exit 1"
result = run_rscons(args: %W[-f #{rsconscript} configure])
expect(result.stderr).to match /Configuration failed/
expect(result.stderr).to match %r{Configuration failed; log file written to build/_configure/config.log}
expect(result.status).to_not eq 0
expect(result.stdout).to match /Checking for C compiler\.\.\. not found/
expect(result.stdout).to match /Checking for C compiler\.\.\. not found \(checked gcc, clang\)/
end
end
end
@@ -1987,9 +1992,9 @@ EOF
create_exe "g++", "exit 1"
create_exe "clang++", "exit 1"
result = run_rscons(args: %W[-f #{rsconscript} configure])
expect(result.stderr).to match /Configuration failed/
expect(result.stderr).to match %r{Configuration failed; log file written to build/_configure/config.log}
expect(result.status).to_not eq 0
expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. not found/
expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. not found \(checked g\+\+, clang\+\+\)/
end
end
end
@@ -2042,10 +2047,11 @@ EOF
test_dir "configure"
create_exe "gdc", "exit 1"
create_exe "ldc2", "exit 1"
create_exe "ldc", "exit 1"
result = run_rscons(args: %W[-f #{rsconscript} configure])
expect(result.stderr).to match /Configuration failed/
expect(result.stderr).to match %r{Configuration failed; log file written to build/_configure/config.log}
expect(result.status).to_not eq 0
expect(result.stdout).to match /Checking for D compiler\.\.\. not found/
expect(result.stdout).to match /Checking for D compiler\.\.\. not found \(checked gdc, ldc2, ldc\)/
end
end
end
@@ -2282,6 +2288,18 @@ EOF
expect(result.stdout).to_not match /-lm/
end
it "finds the requested library with only ldc compiler" do
test_dir "configure"
create_exe "gcc", "exit 1"
create_exe "clang", "exit 1"
create_exe "gcc++", "exit 1"
create_exe "clang++", "exit 1"
result = run_rscons(args: %w[-f check_lib_with_ldc.rb])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to match /Checking for library 'z'... found/
end
it "modifies LIBPATH based on check_libpath" do
test_dir "configure"
FileUtils.mkdir_p("usr1")
@@ -2372,6 +2390,13 @@ EOF
expect(result.stdout).to_not match /gcc.*-o.*myconfigtest1.*-DMYPACKAGE/
expect(result.stdout).to match /gcc.*-o.*myconfigtest2.*-DMYPACKAGE/
end
it "indicates that pkg-config command cannot be found" do
test_dir "configure"
result = run_rscons(args: %w[-f check_cfg_no_pkg_config.rb configure])
expect(result.stderr).to match /Error: executable 'pkg-config' not found/
expect(result.status).to_not eq 0
end
end
context "when passed a program" do
@@ -2514,7 +2539,7 @@ EOF
expect(result.stdout).to match /Checking for C compiler\.\.\. not found/
expect(result.status).to_not eq 0
expect(result.stderr).to_not match /from\s/
expect(lines(result.stderr).last).to eq "Configuration failed"
expect(lines(result.stderr).last).to match /Configuration failed/
end
it "does not rebuild after building with auto-configuration" do
@@ -2522,7 +2547,7 @@ EOF
result = run_rscons(args: %w[-f autoconf_rebuild.rb])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(File.exists?("simple.exe")).to be_truthy
expect(File.exist?("simple.exe")).to be_truthy
result = run_rscons(args: %w[-f autoconf_rebuild.rb])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
@@ -2536,13 +2561,13 @@ EOF
result = run_rscons(args: %w[-f distclean.rb])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(File.exists?("simple.o")).to be_truthy
expect(File.exists?("build")).to be_truthy
expect(File.exist?("simple.o")).to be_truthy
expect(File.exist?("build")).to be_truthy
result = run_rscons(args: %w[-f distclean.rb distclean])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(File.exists?("simple.o")).to be_falsey
expect(File.exists?("build")).to be_falsey
expect(File.exist?("simple.o")).to be_falsey
expect(File.exist?("build")).to be_falsey
end
end
@@ -2576,7 +2601,7 @@ EOF
result = run_rscons(args: %w[-f c_program.rb])
expect(result.stderr).to eq ""
expect(result.stdout).to match %r{Compiling/Linking}
expect(File.exists?("test.exe")).to be_truthy
expect(File.exist?("test.exe")).to be_truthy
expect(`./test.exe`).to match /three/
result = run_rscons(args: %w[-f c_program.rb])
@@ -2597,7 +2622,7 @@ EOF
result = run_rscons(args: %w[-f c_shared_library.rb])
expect(result.stderr).to eq ""
expect(result.stdout).to match %r{Compiling/Linking}
expect(File.exists?("test.exe")).to be_truthy
expect(File.exist?("test.exe")).to be_truthy
ld_library_path_prefix = (RUBY_PLATFORM =~ /mingw|msys/ ? "" : "LD_LIBRARY_PATH=. ")
expect(`#{ld_library_path_prefix}./test.exe`).to match /three/
@@ -2651,11 +2676,11 @@ EOF
expect(File.directory?("#{prefix}/bin")).to be_truthy
expect(File.directory?("#{prefix}/src")).to be_truthy
expect(File.directory?("#{prefix}/share")).to be_truthy
expect(File.exists?("#{prefix}/bin/program.exe")).to be_truthy
expect(File.exists?("#{prefix}/src/one/one.c")).to be_truthy
expect(File.exists?("#{prefix}/share/proj/install.rb")).to be_truthy
expect(File.exists?("#{prefix}/mult/install.rb")).to be_truthy
expect(File.exists?("#{prefix}/mult/copy.rb")).to be_truthy
expect(File.exist?("#{prefix}/bin/program.exe")).to be_truthy
expect(File.exist?("#{prefix}/src/one/one.c")).to be_truthy
expect(File.exist?("#{prefix}/share/proj/install.rb")).to be_truthy
expect(File.exist?("#{prefix}/mult/install.rb")).to be_truthy
expect(File.exist?("#{prefix}/mult/copy.rb")).to be_truthy
result = run_rscons(args: %w[-f install.rb install])
expect(result.stderr).to eq ""
@@ -2692,14 +2717,14 @@ EOF
result = run_rscons(args: %w[-f install.rb install])
expect(result.stderr).to eq ""
expect(File.exists?("#{prefix}/bin/program.exe")).to be_truthy
expect(File.exists?("build/e.1/src/one/one.c.o")).to be_truthy
expect(File.exist?("#{prefix}/bin/program.exe")).to be_truthy
expect(File.exist?("build/o/src/one/one.c.o")).to be_truthy
result = run_rscons(args: %w[-f install.rb uninstall])
expect(result.stderr).to eq ""
expect(result.stdout).to_not match /Removing/
expect(File.exists?("#{prefix}/bin/program.exe")).to be_falsey
expect(File.exists?("build/e.1/src/one/one.c.o")).to be_truthy
expect(File.exist?("#{prefix}/bin/program.exe")).to be_falsey
expect(File.exist?("build/o/src/one/one.c.o")).to be_truthy
expect(Dir.entries(prefix)).to match_array %w[. ..]
end
end
@@ -2717,7 +2742,7 @@ EOF
result = run_rscons(args: %w[-f install.rb -v uninstall])
expect(result.stderr).to eq ""
expect(result.stdout).to match %r{Removing #{prefix}/bin/program.exe}
expect(File.exists?("#{prefix}/bin/program.exe")).to be_falsey
expect(File.exist?("#{prefix}/bin/program.exe")).to be_falsey
expect(Dir.entries(prefix)).to match_array %w[. ..]
end
end
@@ -2735,7 +2760,7 @@ EOF
result = run_rscons(args: %w[-f install.rb -v uninstall])
expect(result.stderr).to eq ""
expect(result.stdout).to match %r{Removing #{prefix}/bin/program.exe}
expect(File.exists?("#{prefix}/bin/program.exe")).to be_falsey
expect(File.exist?("#{prefix}/bin/program.exe")).to be_falsey
expect(Dir.entries(prefix)).to match_array %w[. ..]
FileUtils.mkdir_p("#{prefix}/bin")
@@ -3346,6 +3371,13 @@ EOF
" release (enabled)",
])
end
it "raises an error when an unnamed environment is created with multiple active variants" do
test_dir "variants"
result = run_rscons(args: %w[-f error_unnamed_environment.rb])
expect(result.stderr).to match /Error: an Environment with active variants must be given a name/
expect(result.status).to_not eq 0
end
end
context "build_dir method" do
@@ -3366,4 +3398,32 @@ EOF
end
end
if RUBY_PLATFORM =~ /linux/
it "allows writing a binary to an environment's build directory with the same name as a top-level source folder" do
test_dir "typical"
result = run_rscons(args: %w[-f binary_matching_folder.rb])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(File.exist?("build/src/src")).to be_truthy
end
end
it "supports building LLVM assembly files with the Program builder" do
test_dir "llvm"
result = run_rscons
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(File.exist?("llvmtest.exe")).to be_truthy
expect(`./llvmtest.exe`).to match /hello world/
end
it "supports building LLVM assembly files with the Program builder in direct mode" do
test_dir "llvm"
result = run_rscons(args: %w[-f direct.rb])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(File.exist?("llvmtest.exe")).to be_truthy
expect(`./llvmtest.exe`).to match /hello again/
end
end
+8 -8
View File
@@ -17,14 +17,14 @@ module Rscons
it "makes directories and records any created in the cache" do
_cache = {}
cache = build_from(_cache)
expect(File).to receive(:exists?).with("one").and_return(true)
expect(File).to receive(:exists?).with("one/two").and_return(false)
expect(File).to receive(:exist?).with("one").and_return(true)
expect(File).to receive(:exist?).with("one/two").and_return(false)
expect(FileUtils).to receive(:mkdir_p).with("one/two")
expect(File).to receive(:exists?).with("one/two/three").and_return(false)
expect(File).to receive(:exist?).with("one/two/three").and_return(false)
expect(FileUtils).to receive(:mkdir_p).with("one/two/three")
expect(File).to receive(:exists?).with("one").and_return(true)
expect(File).to receive(:exists?).with("one/two").and_return(true)
expect(File).to receive(:exists?).with("one/two/four").and_return(false)
expect(File).to receive(:exist?).with("one").and_return(true)
expect(File).to receive(:exist?).with("one/two").and_return(true)
expect(File).to receive(:exist?).with("one/two/four").and_return(false)
expect(FileUtils).to receive(:mkdir_p).with("one/two/four")
cache.mkdir_p("one/two/three")
cache.mkdir_p("one\\two\\four")
@@ -34,8 +34,8 @@ module Rscons
it "handles absolute paths" do
_cache = {}
cache = build_from(_cache)
expect(File).to receive(:exists?).with("/one").and_return(true)
expect(File).to receive(:exists?).with("/one/two").and_return(false)
expect(File).to receive(:exist?).with("/one").and_return(true)
expect(File).to receive(:exist?).with("/one/two").and_return(false)
expect(FileUtils).to receive(:mkdir_p).with("/one/two")
cache.mkdir_p("/one/two")
expect(cache.directories(false)).to eq ["/one/two"]