Compare commits
50
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d08e2f6b5c | ||
|
|
90365dd197 | ||
|
|
8d05516c40 | ||
|
|
db49d86866 | ||
|
|
e667455c32 | ||
|
|
e62332aba6 | ||
|
|
397639849d | ||
|
|
96d5caf2e5 | ||
|
|
f4b10a30af | ||
|
|
cf52c3fc6f | ||
|
|
5378afb6f8 | ||
|
|
48d9273cc6 | ||
|
|
efea4f1181 | ||
|
|
b4fa6d965c | ||
|
|
ac56ad34f6 | ||
|
|
2fd533a32a | ||
|
|
c938ed71d1 | ||
|
|
ec60201a62 | ||
|
|
0cafb8c5b3 | ||
|
|
004810386b | ||
|
|
a15ee9daaf | ||
|
|
cd33405697 | ||
|
|
efa77066bf | ||
|
|
a1bb9d81fd | ||
|
|
0344f02cb1 | ||
|
|
d52bdaf046 | ||
|
|
ad7ccb771d | ||
|
|
044ee343ca | ||
|
|
eb54a2b64a | ||
|
|
2dd1ce9f1d | ||
|
|
1e157c79ec | ||
|
|
2385874f4a | ||
|
|
c5c42e6f4a | ||
|
|
9a627b2150 | ||
|
|
937c964c3e | ||
|
|
a2a1d08014 | ||
|
|
0ccf43cc96 | ||
|
|
d202e15a57 | ||
|
|
94f808b1fc | ||
|
|
51a9dd365f | ||
|
|
6e590b62a6 | ||
|
|
3aac190ad6 | ||
|
|
d6b9487e65 | ||
|
|
66d2700faa | ||
|
|
ba98af1424 | ||
|
|
cf4f80c9ae | ||
|
|
d74785d579 | ||
|
|
4fd822fb95 | ||
|
|
b39fd80d8c | ||
|
|
ef00c9f377 |
No files matched your search
@@ -1,3 +1,51 @@
|
||||
## v2.0.2
|
||||
|
||||
### Fixes
|
||||
|
||||
- #113 - distinguish object files built from multiple sources with the same base name but different extensions
|
||||
|
||||
## v2.0.1
|
||||
|
||||
### Fixes
|
||||
|
||||
- #112 - Install builder cannot replace a currently executing binary on Linux
|
||||
|
||||
## v2.0.0
|
||||
|
||||
- convert rscons from a Ruby gem to a standalone script
|
||||
- compress rscons distributable script
|
||||
- add configure operation to detect compilers, check for headers/libraries, etc... (invoked automatically if needed)
|
||||
- Environments store builder classes instead of instances of builder classes
|
||||
- use a separate Builder instance for each build operation
|
||||
- load Rsconscript from Rsconscript/Rsconscript.rb instead of Rsconsfile
|
||||
- drop support for builder run methods using the old 5 parameter signature
|
||||
- remove Environment#build_dir
|
||||
- set Environment build root in configure step
|
||||
- remove Builder#finalize (now #run called repeatedly until builder completes)
|
||||
- remove Builder#setup
|
||||
- remove Builder#features and Builder#produces?
|
||||
- add functionality to allow builders to wait on Ruby threads or other builders
|
||||
- add install/uninstall/distclean command-line operations
|
||||
- preserve makefile dependency files under build directory
|
||||
- remove a few deprecated methods
|
||||
- pass a Builder instance to build hooks instead of a build operation Hash
|
||||
- support a basic markup syntax in builder run messages to colorize target/source files
|
||||
- hide (but store) failed compilation command by default so the user doesn't have to scroll back as much to see compiler output
|
||||
- refactor to remove some redundancy among built-in builders
|
||||
- track object file source language (correctly determine linker when only passed object files previously built by particular toolchains)
|
||||
- add barriers
|
||||
- add InstallDirectory builder
|
||||
- change Install builder to copy files on 'install' operation
|
||||
- add "prefix" construction variable based on configured installation prefix
|
||||
- allow passing builder objects as sources to build targets
|
||||
- differentiate 'build' targets from 'install' targets in cache contents
|
||||
- add verbose mode
|
||||
- show build progress as a percentage in builder output messages
|
||||
- various performance improvements
|
||||
- wrote a new user guide
|
||||
- added new website ([https://holtrop.github.io/rscons/](https://holtrop.github.io/rscons/))
|
||||
- added new logo
|
||||
|
||||
## v1.17.0
|
||||
|
||||
### New Features
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# Rscons
|
||||
|
||||

|
||||
|
||||
Rscons (https://github.com/holtrop/rscons) is an open-source build system
|
||||
for developers.
|
||||
|
||||
Rscons is written in Ruby, and is inspired by [SCons](https://scons.org/) and [waf](https://waf.io/).
|
||||
|
||||
See [https://holtrop.github.io/rscons/index.html](https://holtrop.github.io/rscons/index.html) for User Guide and Installation instructions.
|
||||
+8
-1
@@ -11,7 +11,7 @@ require "rake/clean"
|
||||
require "fileutils"
|
||||
|
||||
CLEAN.include %w[build_test_run .yardoc yard coverage test]
|
||||
CLOBBER.include %w[dist pkg]
|
||||
CLOBBER.include %w[dist gen large_project pkg]
|
||||
|
||||
task :build_dist do
|
||||
sh "ruby rb/build_dist.rb"
|
||||
@@ -93,3 +93,10 @@ task :user_guide do
|
||||
end
|
||||
|
||||
task :default => :spec
|
||||
|
||||
task :all => [
|
||||
:build_dist,
|
||||
:spec,
|
||||
:yard,
|
||||
:user_guide,
|
||||
]
|
||||
@@ -0,0 +1,10 @@
|
||||
configure do
|
||||
check_c_header "string.h", check_cpppath: ["./usr1"]
|
||||
check_c_header "frobulous.h", check_cpppath: ["./usr2"]
|
||||
end
|
||||
|
||||
build do
|
||||
Environment.new do |env|
|
||||
env.Object("test.o", "test.c")
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
configure do
|
||||
check_c_header "not___found.h", fail: false, set_define: "HAVE_NOT___FOUND_H"
|
||||
check_c_header "not___found.h", set_define: "HAVE_NOT___FOUND_H"
|
||||
end
|
||||
|
||||
build do
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
configure do
|
||||
check_cxx_header "string.h", check_cpppath: ["./usr1"]
|
||||
check_cxx_header "frobulous.h", check_cpppath: ["./usr2"]
|
||||
end
|
||||
|
||||
build do
|
||||
Environment.new do |env|
|
||||
env.Object("test.o", "test.cc")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
configure do
|
||||
check_d_import "std.stdio", check_d_import_path: ["./usr1"]
|
||||
check_d_import "frobulous", check_d_import_path: ["./usr2"]
|
||||
end
|
||||
|
||||
build do
|
||||
Environment.new do |env|
|
||||
env.Object("test.o", "test.d")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
build do
|
||||
Environment.new(echo: :command) do |env|
|
||||
env.Library("usr2/libfrobulous.a", "two.c")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
configure do
|
||||
check_lib "m", check_libpath: ["./usr1"]
|
||||
check_lib "frobulous", check_libpath: ["./usr2"]
|
||||
end
|
||||
|
||||
build do
|
||||
Environment.new(echo: :command) do |env|
|
||||
env.Program("simple.exe", "simple.c")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
configure do
|
||||
custom_check("Checking 'grep' version") do |op|
|
||||
stdout, stderr, status = op.log_and_test_command(%w[grep --version])
|
||||
should_fail = true
|
||||
if status != 0
|
||||
fail_message = "error executing grep"
|
||||
elsif stdout =~ /^grep \(GNU grep\) 1\./
|
||||
fail_message = "too old!"
|
||||
status = 1
|
||||
elsif stdout =~ /^grep \(GNU grep\) 2\./
|
||||
fail_message = "we'll work with it but you should upgrade"
|
||||
status = 1
|
||||
should_fail = false
|
||||
op.store_merge("CPPDEFINES" => "GREP_WORKAROUND")
|
||||
else
|
||||
op.store_append("CPPDEFINES" => "GREP_FULL")
|
||||
end
|
||||
op.complete(status, success_message: "good!", fail_message: fail_message, fail: should_fail)
|
||||
end
|
||||
custom_check("Checking sed -E flag") do |op|
|
||||
stdout, stderr, status = op.log_and_test_command(%w[sed -E -e s/ab+/rep/], stdin: "abbbc")
|
||||
op.complete(stdout =~ /repc/ ? 0 : 1, success_message: "good", fail_message: "fail")
|
||||
end
|
||||
end
|
||||
|
||||
build do
|
||||
Environment.new do |env|
|
||||
puts env["CPPDEFINES"]
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
int two(void)
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
@@ -6,7 +6,8 @@ build do
|
||||
"CMD_DESC" => "Generating")
|
||||
env["build_root"] = env.build_root
|
||||
env["inc_c"] = "inc.c"
|
||||
env.build_after("${build_root}/program.o", "${inc_c}")
|
||||
env.Program("program.exe", ["program.c", "inc.c"])
|
||||
env.Object("program.o", "program.c")
|
||||
env.build_after("program.o", "${inc_c}")
|
||||
env.Program("program.exe", ["program.o", "inc.c"])
|
||||
end
|
||||
end
|
||||
@@ -4,8 +4,9 @@ build do
|
||||
env["inc_h"] = "inc.h"
|
||||
|
||||
env.Copy("copy_inc.h", "${inc_h}")
|
||||
env.depends("${build_root}/program.o", "${inc_h}")
|
||||
env.Program("program.exe", ["program.c", "inc.c"])
|
||||
env.depends("program.o", "${inc_h}")
|
||||
env.Object("program.o", "program.c")
|
||||
env.Program("program.exe", ["program.o", "inc.c"])
|
||||
|
||||
inc_c = env.Command("inc.c",
|
||||
[],
|
||||
|
||||
@@ -4,8 +4,9 @@ build do
|
||||
env["inc_h"] = "inc.h"
|
||||
|
||||
env.Copy("copy_inc.h", "${inc_h}")
|
||||
env.depends("${build_root}/program.o", "${inc_h}")
|
||||
env.Program("program.exe", ["program.c", "inc.c"])
|
||||
env.depends("program.o", "${inc_h}")
|
||||
env.Object("program.o", "program.c")
|
||||
env.Program("program.exe", ["program.o", "inc.c"])
|
||||
|
||||
env.Command("inc.c",
|
||||
[],
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
configure do
|
||||
check_d_compiler "gdc"
|
||||
end
|
||||
|
||||
build do
|
||||
Environment.new(echo: :command) do |env|
|
||||
env.Program("hello-d.exe", glob("*.d"))
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
configure do
|
||||
check_d_compiler "ldc2"
|
||||
end
|
||||
|
||||
build do
|
||||
Environment.new(echo: :command) do |env|
|
||||
env.Program("hello-d.exe", glob("*.d"))
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
build do
|
||||
Environment.new do |env|
|
||||
env.Program("program.exe", "program.c")
|
||||
env.Install("install/program.exe", "program.exe")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
sleep(2);
|
||||
return 0;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ build do
|
||||
require 'yaml'
|
||||
env.add_builder(:JsonToYaml) do |params|
|
||||
unless @cache.up_to_date?(@target, :JsonToYaml, @sources, @env)
|
||||
print_run_message("JsonToYaml #{@target}", nil)
|
||||
@cache.mkdir_p(File.dirname(@target))
|
||||
File.open(@target, 'w') do |f|
|
||||
f.write(YAML.dump(JSON.load(IO.read(@sources.first))))
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
build do
|
||||
Environment.new do |env|
|
||||
env.Program("foo.exe", glob("*.cc", "*.c"))
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void foo(void)
|
||||
{
|
||||
printf("foo\n");
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <iostream>
|
||||
|
||||
extern "C" {
|
||||
void foo(void);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
foo();
|
||||
std::cout << "main" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
build do
|
||||
Environment.new do |env|
|
||||
env["LIBS"] += ["c"]
|
||||
env["LIBS"] += ["m"]
|
||||
env.Program('simple.exe', Dir['*.c'])
|
||||
end
|
||||
end
|
||||
@@ -2,9 +2,9 @@ build do
|
||||
Environment.new(echo: :command) do |env|
|
||||
env.append('CPPPATH' => glob('src/**/*/'))
|
||||
env.add_build_hook do |builder|
|
||||
if File.basename(builder.target) == "one.o"
|
||||
if File.basename(builder.sources.first) == "one.c"
|
||||
builder.vars["CFLAGS"] << "-O1"
|
||||
elsif File.basename(builder.target) == "two.o"
|
||||
elsif File.basename(builder.sources.first) == "two.c"
|
||||
builder.vars["CFLAGS"] << "-O2"
|
||||
end
|
||||
end
|
||||
|
||||
+201
-9
@@ -8,7 +8,7 @@ It supports the following features:
|
||||
* built-in builders for several common operations
|
||||
* out-of-the-box support for C, C++, and D languages
|
||||
* extensibility for other languages or custom builders
|
||||
* compatible with Windows, Linux, and OS X
|
||||
* compatible with Windows, Linux, OS X, and FreeBSD
|
||||
* colorized output with build progress
|
||||
* build hooks
|
||||
|
||||
@@ -24,6 +24,15 @@ custom build operations as well.
|
||||
|
||||
Rscons is written in Ruby, and is inspired by [SCons](https://scons.org/) and [waf](https://waf.io/).
|
||||
|
||||
${remove}
|
||||
WARNING: This user guide is meant to be preprocessed and rendered by a custom
|
||||
script.
|
||||
The markdown source file is not intended to be viewed directly and will not
|
||||
include all intended content.
|
||||
Visit [https://holtrop.github.io/rscons/index.html](https://holtrop.github.io/rscons/index.html)
|
||||
to view the properly rendered version.
|
||||
${/remove}
|
||||
|
||||
## Design Principles
|
||||
|
||||
### Build Correctness
|
||||
@@ -89,7 +98,8 @@ The only dependency required to run Rscons is to have a Ruby interpreter
|
||||
installed.
|
||||
The latest release can be downloaded from [https://github.com/holtrop/rscons/releases](https://github.com/holtrop/rscons/releases).
|
||||
Simply copy the `rscons` executable script into the desired location within
|
||||
the project to be built (typically the root of the repository).
|
||||
the project to be built (typically the root of the repository) and mark it
|
||||
executable.
|
||||
|
||||
## Version Control Setup
|
||||
|
||||
@@ -131,6 +141,7 @@ Such configuration checks can include:
|
||||
* verifying presence of a D import
|
||||
* verifying presence of a library
|
||||
* verifying presence of an executable
|
||||
* any custom user-supplied configuration check
|
||||
|
||||
##> Build Operation
|
||||
|
||||
@@ -140,6 +151,17 @@ been performed, a `configure` operation will be automatically invoked.
|
||||
The `build` operation will execute all builders registered to produce build
|
||||
targets.
|
||||
|
||||
If a `build` operation fails (e.g. due to a compilation failure), Rscons will
|
||||
log the failed commands.
|
||||
By default Rscons does not print the failed commands to the console so that it
|
||||
is easier for the user to focus on the actual compiler failure messages rather
|
||||
than the compilation command itself.
|
||||
However, if the user wishes to see the compilation commands, rscons can be
|
||||
invoked with the `-v` command-line option to show all complilation commands
|
||||
while building, or, alternatively, following a compilation failure, the user
|
||||
can invoke rscons with the -F option which will not rebuild but will show the
|
||||
failed command log from the previous build operation.
|
||||
|
||||
##> Clean Operation
|
||||
|
||||
A `clean` operation will remove all built target files.
|
||||
@@ -211,6 +233,7 @@ working compiler:
|
||||
|
||||
Each of these methods can take an optional list of compilers to check for.
|
||||
If such a list is supplied, the compilers are tested in the order listed.
|
||||
The first compiler option found which passes a compilation test is used.
|
||||
|
||||
Here are example calls which also show the default compiler list for each
|
||||
supported language:
|
||||
@@ -237,7 +260,7 @@ Example calls:
|
||||
|
||||
```ruby
|
||||
configure do
|
||||
check_c_header "getopt.h", fail: false, set_define: "HAVE_GETOPT_H"
|
||||
check_c_header "getopt.h", set_define: "HAVE_GETOPT_H"
|
||||
check_c_header "FreeType2.h"
|
||||
check_cxx_header "memory"
|
||||
end
|
||||
@@ -245,10 +268,16 @@ end
|
||||
|
||||
#### Options
|
||||
|
||||
##### `:check_cpppath`
|
||||
|
||||
Optionally specifies an array of paths to look for the header file in.
|
||||
|
||||
##### `:fail`
|
||||
|
||||
If the `:fail` option is set to `false`, then the absence of the header file
|
||||
will not result in the configure option failing.
|
||||
The `:fail` option defaults to `true` if the `:set_define` option is not
|
||||
defined, and defaults to `false` if the `:set_define` option is defined.
|
||||
|
||||
##### `:set_define`
|
||||
|
||||
@@ -270,6 +299,12 @@ configure do
|
||||
end
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
##### `:check_d_import_path`
|
||||
|
||||
Optionally specifies an array of paths to look for the module in.
|
||||
|
||||
###> Checking for a Library
|
||||
|
||||
The `check_lib` method can be used to check for the presence of a library.
|
||||
@@ -288,16 +323,28 @@ end
|
||||
|
||||
#### Options
|
||||
|
||||
##### `:check_libpath`
|
||||
|
||||
Optionally specifies an array of paths to look for the library in.
|
||||
|
||||
##### `:fail`
|
||||
|
||||
If the `:fail` option is set to `false`, then the absence of the library
|
||||
will not result in the configure option failing.
|
||||
The `:fail` option defaults to `true` if the `:set_define` option is not
|
||||
defined, and defaults to `false` if the `:set_define` option is defined.
|
||||
|
||||
##### `:set_define`
|
||||
|
||||
If set, a build define of the specified String will be added to the
|
||||
`CPPDEFINES` construction variable array if the requested library is found.
|
||||
|
||||
##### `:use`
|
||||
|
||||
If not set, the library will be used by default in all `Environment` objects.
|
||||
If set, the library will only be used in `Environment` objects that have a
|
||||
matching `:use` flag set.
|
||||
|
||||
###> Checking for a Program
|
||||
|
||||
The `check_program` method can check for the existence of an executable in the
|
||||
@@ -344,12 +391,72 @@ for configuration flags.
|
||||
|
||||
If the `:fail` option is set to `false`, then the absence of the package or
|
||||
program requested will not result in the configure option failing.
|
||||
The `:fail` option defaults to `true` if the `:set_define` option is not
|
||||
defined, and defaults to `false` if the `:set_define` option is defined.
|
||||
|
||||
##### `:set_define`
|
||||
|
||||
If set, a build define of the specified String will be added to the
|
||||
`CPPDEFINES` construction variable array if the requested package is found.
|
||||
|
||||
##### `:use`
|
||||
|
||||
If not set, the library will be used by default in all `Environment` objects.
|
||||
If set, the library will only be used in `Environment` objects that have a
|
||||
matching `:use` flag set.
|
||||
|
||||
###> Custom Configuration Checks
|
||||
|
||||
The `Rsconscript` author can add custom configuration checks to be performed
|
||||
during the rscons `configure` operation.
|
||||
|
||||
Here is an example from `build_tests/configure/custom_config_check.rb` showing
|
||||
a custom configuration check:
|
||||
|
||||
```ruby
|
||||
${include build_tests/configure/custom_config_check.rb}
|
||||
```
|
||||
|
||||
A custom configuration check is created by calling the `custom_check` method
|
||||
and passing a block.
|
||||
The contents of the block should perform the custom configuration checking
|
||||
logic.
|
||||
This logic can include executing a test command or other arbitrary operations.
|
||||
An argument `op` is passed to the block.
|
||||
This object is an instance of the [`ConfigureOp` class](../yard/Rscons/ConfigureOp.html)
|
||||
class and provides several methods that can be used to aid with the custom
|
||||
configuration check.
|
||||
The [`log_and_test_command`](../yard/Rscons/ConfigureOp.html#log_and_test_command-instance_method)
|
||||
method can be used to execute a test command and retrieve its results.
|
||||
The command and its output are also logged to the config.log file.
|
||||
The [`store_merge`](../yard/Rscons/ConfigureOp.html#store_merge-instance_method),
|
||||
[`store_append`](../yard/Rscons/ConfigureOp.html#store_append-instance_method),
|
||||
and [`store_parse`](../yard/Rscons/ConfigureOp.html#store_parse-instance_method)
|
||||
methods can be used to store construction variables for Environments created
|
||||
during the `build` operation.
|
||||
Finally, the [`complete`](../yard/Rscons/ConfigureOp.html#complete-instance_method)
|
||||
method can be used to complete the configuration check and indicate a success
|
||||
or failure.
|
||||
|
||||
While performing a custom configuration check, it can sometimes be useful to
|
||||
be able to construct an Environment to use the set of default construction
|
||||
variables as defined so far in the configuration block, for example to expand
|
||||
construction variables to build a test command.
|
||||
The normal `Environment` class cannot be used within the `configure` block,
|
||||
however the [`BasicEnvironment`](../yard/Rscons/BasicEnvironment.html) class
|
||||
can be used for such a purpose.
|
||||
|
||||
For example, to expand the current `${CCCMD}` value:
|
||||
|
||||
```ruby
|
||||
configure do
|
||||
custom_check("Checking something to do with CCCMD") do
|
||||
command = BasicEnvironment.new.expand_varref("${CCCMD}")
|
||||
# ...
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
##> Build Operations
|
||||
|
||||
The `build` block is used to create Environments and register build targets.
|
||||
@@ -399,7 +506,8 @@ files.
|
||||
|
||||
###> Specifying Source Files: The glob Method
|
||||
|
||||
The `glob` method can be used to find files matching the patterns specified.
|
||||
The [`glob`](../yard/Rscons/Script/Dsl.html#glob-instance_method) method can be
|
||||
used to find files matching the patterns specified.
|
||||
It supports a syntax similar to the Ruby [Dir.glob method](https://ruby-doc.org/core-2.5.1/Dir.html#method-c-glob) but operates more deterministically.
|
||||
|
||||
Example use:
|
||||
@@ -622,6 +730,24 @@ A platform-dependent program suffix will be appended to the target name if one
|
||||
is not specified.
|
||||
This can be controlled with the `PROGSUFFIX` construction variable.
|
||||
|
||||
##### Direct Mode
|
||||
|
||||
The Program builder supports a "direct" mode which is activated by specifying
|
||||
the `:direct` option.
|
||||
In the direct mode, all source files are passed directly to the compiler
|
||||
together and compiled and linked in one step, rather than being individually
|
||||
compiled to separate object files first.
|
||||
This mode allows taking advantage of any multi-file compilation capabilities
|
||||
of the compiler.
|
||||
However, it also requires recompiling all source files when any one of them
|
||||
has changed.
|
||||
|
||||
Example use:
|
||||
|
||||
```ruby
|
||||
env.Program("myprog", Rscons.glob("src/**/*.c"), direct: true)
|
||||
```
|
||||
|
||||
####> The SharedLibrary Builder
|
||||
|
||||
```ruby
|
||||
@@ -638,6 +764,24 @@ they are not specified by the user.
|
||||
These values can be controlled by overriding the `SHLIBPREFIX` and
|
||||
`SHLIBSUFFIX` construction variables.
|
||||
|
||||
##### Direct Mode
|
||||
|
||||
The SharedLibrary builder supports a "direct" mode which is activated by
|
||||
specifying the `:direct` option.
|
||||
In the direct mode, all source files are passed directly to the compiler
|
||||
together and compiled and linked in one step, rather than being individually
|
||||
compiled to separate object files first.
|
||||
This mode allows taking advantage of any multi-file compilation capabilities
|
||||
of the compiler.
|
||||
However, it also requires recompiling all source files when any one of them
|
||||
has changed.
|
||||
|
||||
Example use:
|
||||
|
||||
```ruby
|
||||
env.SharedLibrary("mydll", Rscons.glob("src/**/*.c"), direct: true)
|
||||
```
|
||||
|
||||
####> The SharedObject Builder
|
||||
|
||||
```ruby
|
||||
@@ -703,6 +847,18 @@ Post-build hooks are only invoked if the build operation was a success.
|
||||
|
||||
Build hooks and post-build hooks can register new build targets.
|
||||
|
||||
###> Barriers
|
||||
|
||||
Normally Rscons will parallelize all builders.
|
||||
A barrier can be used to separate sets of build targets.
|
||||
All build targets registered before the barrier is created will be built before
|
||||
Rscons will schedule any build targets after the barrier.
|
||||
In other words, build targets are not parallelized across a barrier.
|
||||
|
||||
```ruby
|
||||
env.barrier
|
||||
```
|
||||
|
||||
##> Extending Rscons
|
||||
|
||||
### Adding New Languages
|
||||
@@ -869,7 +1025,7 @@ Here is our Custom builder example extended to print its status:
|
||||
```ruby
|
||||
class Rscons::Builders::Custom < Rscons::Builder
|
||||
def run(options)
|
||||
print_run_message("Creating <target>#{@target}<reset> from Custom builder")
|
||||
print_run_message("Creating <target>#{@target}<reset> from Custom builder", nil)
|
||||
File.open(@target, "w") do |fh|
|
||||
fh.write("Target file created.")
|
||||
end
|
||||
@@ -894,7 +1050,7 @@ Here is a Custom builder which combines its source files similar to what the
|
||||
class Rscons::Builders::Custom < Rscons::Builder
|
||||
def run(options)
|
||||
unless @cache.up_to_date?(@target, nil, @sources, @env)
|
||||
print_run_message("Combining <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>")
|
||||
print_run_message("Combining <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", nil)
|
||||
File.open(@target, "wb") do |fh|
|
||||
@sources.each do |source|
|
||||
fh.write(File.read(source, mode: "rb"))
|
||||
@@ -952,9 +1108,9 @@ the `Rscons::Command` class and then `wait_for` the Command object.
|
||||
However, this is a common enough case that Rscons provides a few
|
||||
convenience methods to handle this:
|
||||
|
||||
* `Rscons::Builder#register_command`
|
||||
* `Rscons::Builder#standard_command`
|
||||
* `Rscons::Builder#finalize_command`
|
||||
* [`Rscons::Builder#register_command`](../yard/Rscons/Builder.html#register_command-instance_method)
|
||||
* [`Rscons::Builder#standard_command`](../yard/Rscons/Builder.html#standard_command-instance_method)
|
||||
* [`Rscons::Builder#finalize_command`](../yard/Rscons/Builder.html#finalize_command-instance_method)
|
||||
|
||||
The `register_command` helper method can be used to create a Command object
|
||||
and wait for it to complete.
|
||||
@@ -1104,6 +1260,42 @@ build do
|
||||
end
|
||||
```
|
||||
|
||||
##> ./configure && make
|
||||
|
||||
You can make your Rscons-based project more familiar to users of
|
||||
autoconf-generated projects by creating a `configure` script and a `Makefile`
|
||||
for the user.
|
||||
Such users may be used to executing:
|
||||
|
||||
```
|
||||
./configure
|
||||
make
|
||||
```
|
||||
|
||||
to build a project.
|
||||
To do this, create a `configure` script with contents similar to the following:
|
||||
|
||||
```
|
||||
#!/bin/sh
|
||||
exec "$(dirname "$0")"/rscons configure "$@"
|
||||
```
|
||||
|
||||
and make it executable with `chmod +x configure`.
|
||||
|
||||
If you want your users to be able to build/clean a project with `make` but
|
||||
still make use of Rscons under the hood, you can create a `Makefile` with
|
||||
contents something like this:
|
||||
|
||||
```
|
||||
.PHONY: all
|
||||
all:
|
||||
./rscons build
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
./rscons clean
|
||||
```
|
||||
|
||||
##> YARD API Documentation
|
||||
|
||||
See [here](../yard/index.html) for Rscons YARD API Documentation.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
@@ -64,16 +64,6 @@ module Rscons
|
||||
target.is_a?(Symbol)
|
||||
end
|
||||
|
||||
# Return a new path by changing the suffix in path to suffix.
|
||||
#
|
||||
# @param path [String] The path to alter.
|
||||
# @param suffix [String] The new filename suffix, e.g. ".exe".
|
||||
#
|
||||
# @return [String] New path.
|
||||
def set_suffix(path, suffix)
|
||||
path.sub(/\.[^.]*$/, "") + suffix
|
||||
end
|
||||
|
||||
# Return the system shell and arguments for executing a shell command.
|
||||
#
|
||||
# @return [Array<String>] The shell and flag.
|
||||
|
||||
@@ -3,6 +3,7 @@ module Rscons
|
||||
module Ansi
|
||||
class << self
|
||||
|
||||
# ANSI terminal reset sequence.
|
||||
RESET = "\e[0m"
|
||||
|
||||
# Write a message to an IO with ANSI escape codes.
|
||||
|
||||
@@ -75,6 +75,8 @@ module Rscons
|
||||
end
|
||||
if rv == 0
|
||||
build(operation_options)
|
||||
else
|
||||
rv
|
||||
end
|
||||
when "clean"
|
||||
clean
|
||||
@@ -192,6 +194,7 @@ module Rscons
|
||||
begin
|
||||
@script.configure(co)
|
||||
rescue ConfigureOp::ConfigureFailure
|
||||
Ansi.write($stderr, :red, "Configuration failed", :reset, "\n")
|
||||
rv = 1
|
||||
end
|
||||
co.close(rv == 0)
|
||||
|
||||
@@ -4,10 +4,11 @@ module Rscons
|
||||
|
||||
# Create a BasicEnvironment object.
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param options [Hash]
|
||||
# Construction options.
|
||||
# @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.
|
||||
def initialize(options = {})
|
||||
@varset = VarSet.new(Rscons::DEFAULT_CONSTRUCTION_VARIABLES)
|
||||
load_configuration_data!(options)
|
||||
|
||||
@@ -57,6 +57,7 @@ module Rscons
|
||||
printed_message = true
|
||||
end
|
||||
@cache.mkdir_p(File.dirname(dest), install: @install_builder)
|
||||
FileUtils.rm_f(dest)
|
||||
FileUtils.cp(src, dest, :preserve => true)
|
||||
end
|
||||
@cache.register_build(dest, :Copy, [src], @env, install: @install_builder)
|
||||
|
||||
@@ -9,7 +9,7 @@ module Rscons
|
||||
def finalize_command_with_depfile
|
||||
deps = @sources
|
||||
if File.exists?(@vars["_DEPFILE"])
|
||||
deps += Util.parse_makefile_deps(@vars["_DEPFILE"])
|
||||
deps += Util.parse_dependency_file(@vars["_DEPFILE"])
|
||||
end
|
||||
@cache.register_build(@target, @command, deps.uniq, @env)
|
||||
true
|
||||
|
||||
@@ -8,6 +8,7 @@ module Rscons
|
||||
|
||||
module Builders
|
||||
module Mixins
|
||||
# Mixin for builders needing to build object files.
|
||||
module Object
|
||||
|
||||
include Depfile
|
||||
@@ -77,7 +78,7 @@ module Rscons
|
||||
if @vars[:direct]
|
||||
@env.get_build_fname(target, depfilesuffix, self.class)
|
||||
else
|
||||
Rscons.set_suffix(target, depfilesuffix)
|
||||
"#{target}#{depfilesuffix}"
|
||||
end
|
||||
@cache.mkdir_p(File.dirname(@vars["_DEPFILE"]))
|
||||
command = @env.build_command(@command_template, @vars)
|
||||
|
||||
@@ -23,7 +23,7 @@ module Rscons
|
||||
@vars["_PREPROCESS_DEPGEN"] = depgen
|
||||
@vars["_TARGET"] = @target
|
||||
@vars["_SOURCES"] = @sources
|
||||
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
||||
@vars["_DEPFILE"] = "#{target}#{env.expand_varref("${DEPFILESUFFIX}", vars)}"
|
||||
command = @env.build_command("${CPP_CMD}", @vars)
|
||||
self.produces(@vars["_DEPFILE"])
|
||||
standard_command("Preprocessing <source>#{Util.short_format_paths(@sources)}<reset> => <target>#{@target}<reset>", command)
|
||||
|
||||
@@ -8,6 +8,8 @@ module Rscons
|
||||
include Mixins::Program
|
||||
|
||||
class << self
|
||||
# Custom new method which will delegate to the correct class depending
|
||||
# on the options specified.
|
||||
def new(options, *more)
|
||||
unless File.basename(options[:target])["."]
|
||||
options[:target] += options[:env].expand_varref("${PROGSUFFIX}", options[:vars])
|
||||
|
||||
@@ -8,6 +8,8 @@ module Rscons
|
||||
include Mixins::Program
|
||||
|
||||
class << self
|
||||
# Custom new method which will delegate to the correct class depending
|
||||
# on the options specified.
|
||||
def new(options, *more)
|
||||
libprefix = options[:env].expand_varref("${SHLIBPREFIX}", options[:vars])
|
||||
unless File.basename(options[:target]).start_with?(libprefix)
|
||||
|
||||
@@ -7,6 +7,8 @@ module Rscons
|
||||
include Mixins::Object
|
||||
|
||||
class << self
|
||||
# Content component to add to build path to separate objects built
|
||||
# using this builder from others.
|
||||
def extra_path
|
||||
"_shared"
|
||||
end
|
||||
|
||||
+2
-1
@@ -1,11 +1,12 @@
|
||||
require "rscons"
|
||||
require "optparse"
|
||||
|
||||
# CLI usage string.
|
||||
USAGE = <<EOF
|
||||
Usage: #{$0} [global options] [operation] [operation options]
|
||||
|
||||
Global options:
|
||||
-F, --show-failure Show previous failed command(s) and exit
|
||||
-F, --show-failure Show failed command log from previous build and exit
|
||||
--version Show rscons version and exit
|
||||
-h, --help Show rscons help and exit
|
||||
-r COLOR, --color=COLOR Set color mode (off, auto, force)
|
||||
|
||||
+202
-107
@@ -69,7 +69,7 @@ module Rscons
|
||||
cc = ccc.find do |cc|
|
||||
test_c_compiler(cc)
|
||||
end
|
||||
common_config_checks(cc ? 0 : 1, success_message: cc)
|
||||
complete(cc ? 0 : 1, success_message: cc)
|
||||
end
|
||||
|
||||
# Check for a working C++ compiler.
|
||||
@@ -87,7 +87,7 @@ module Rscons
|
||||
cc = ccc.find do |cc|
|
||||
test_cxx_compiler(cc)
|
||||
end
|
||||
common_config_checks(cc ? 0 : 1, success_message: cc)
|
||||
complete(cc ? 0 : 1, success_message: cc)
|
||||
end
|
||||
|
||||
# Check for a working D compiler.
|
||||
@@ -105,7 +105,7 @@ module Rscons
|
||||
dc = cdc.find do |dc|
|
||||
test_d_compiler(dc)
|
||||
end
|
||||
common_config_checks(dc ? 0 : 1, success_message: dc)
|
||||
complete(dc ? 0 : 1, success_message: dc)
|
||||
end
|
||||
|
||||
# Check for a package or configure program output.
|
||||
@@ -122,11 +122,12 @@ module Rscons
|
||||
if status == 0
|
||||
store_parse(stdout, options)
|
||||
end
|
||||
common_config_checks(status, options)
|
||||
complete(status, options)
|
||||
end
|
||||
|
||||
# Check for a C header.
|
||||
def check_c_header(header_name, options = {})
|
||||
check_cpppath = [nil] + (options[:check_cpppath] || [])
|
||||
Ansi.write($stdout, "Checking for C header '", :cyan, header_name, :reset, "'... ")
|
||||
File.open("#{@work_dir}/cfgtest.c", "wb") do |fh|
|
||||
fh.puts <<-EOF
|
||||
@@ -139,15 +140,30 @@ module Rscons
|
||||
vars = {
|
||||
"LD" => "${CC}",
|
||||
"_SOURCES" => "#{@work_dir}/cfgtest.c",
|
||||
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
||||
"_TARGET" => "#{@work_dir}/cfgtest.o",
|
||||
"_DEPFILE" => "#{@work_dir}/cfgtest.mf",
|
||||
}
|
||||
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
||||
_, _, status = log_and_test_command(command)
|
||||
common_config_checks(status, options)
|
||||
status = 1
|
||||
check_cpppath.each do |cpppath|
|
||||
env = BasicEnvironment.new
|
||||
if cpppath
|
||||
env["CPPPATH"] += Array(cpppath)
|
||||
end
|
||||
command = env.build_command("${CCCMD}", vars)
|
||||
_, _, status = log_and_test_command(command)
|
||||
if status == 0
|
||||
if cpppath
|
||||
store_append({"CPPPATH" => Array(cpppath)}, options)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
complete(status, options)
|
||||
end
|
||||
|
||||
# Check for a C++ header.
|
||||
def check_cxx_header(header_name, options = {})
|
||||
check_cpppath = [nil] + (options[:check_cpppath] || [])
|
||||
Ansi.write($stdout, "Checking for C++ header '", :cyan, header_name, :reset, "'... ")
|
||||
File.open("#{@work_dir}/cfgtest.cxx", "wb") do |fh|
|
||||
fh.puts <<-EOF
|
||||
@@ -160,15 +176,30 @@ module Rscons
|
||||
vars = {
|
||||
"LD" => "${CXX}",
|
||||
"_SOURCES" => "#{@work_dir}/cfgtest.cxx",
|
||||
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
||||
"_TARGET" => "#{@work_dir}/cfgtest.o",
|
||||
"_DEPFILE" => "#{@work_dir}/cfgtest.mf",
|
||||
}
|
||||
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
||||
_, _, status = log_and_test_command(command)
|
||||
common_config_checks(status, options)
|
||||
status = 1
|
||||
check_cpppath.each do |cpppath|
|
||||
env = BasicEnvironment.new
|
||||
if cpppath
|
||||
env["CPPPATH"] += Array(cpppath)
|
||||
end
|
||||
command = env.build_command("${CXXCMD}", vars)
|
||||
_, _, status = log_and_test_command(command)
|
||||
if status == 0
|
||||
if cpppath
|
||||
store_append({"CPPPATH" => Array(cpppath)}, options)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
complete(status, options)
|
||||
end
|
||||
|
||||
# Check for a D import.
|
||||
def check_d_import(d_import, options = {})
|
||||
check_d_import_path = [nil] + (options[:check_d_import_path] || [])
|
||||
Ansi.write($stdout, "Checking for D import '", :cyan, d_import, :reset, "'... ")
|
||||
File.open("#{@work_dir}/cfgtest.d", "wb") do |fh|
|
||||
fh.puts <<-EOF
|
||||
@@ -181,15 +212,30 @@ module Rscons
|
||||
vars = {
|
||||
"LD" => "${DC}",
|
||||
"_SOURCES" => "#{@work_dir}/cfgtest.d",
|
||||
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
||||
"_TARGET" => "#{@work_dir}/cfgtest.o",
|
||||
"_DEPFILE" => "#{@work_dir}/cfgtest.mf",
|
||||
}
|
||||
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
||||
_, _, status = log_and_test_command(command)
|
||||
common_config_checks(status, options)
|
||||
status = 1
|
||||
check_d_import_path.each do |d_import_path|
|
||||
env = BasicEnvironment.new
|
||||
if d_import_path
|
||||
env["D_IMPORT_PATH"] += Array(d_import_path)
|
||||
end
|
||||
command = env.build_command("${DCCMD}", vars)
|
||||
_, _, status = log_and_test_command(command)
|
||||
if status == 0
|
||||
if d_import_path
|
||||
store_append({"D_IMPORT_PATH" => Array(d_import_path)}, options)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
complete(status, options)
|
||||
end
|
||||
|
||||
# Check for a library.
|
||||
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|
|
||||
fh.puts <<-EOF
|
||||
@@ -204,19 +250,150 @@ module Rscons
|
||||
"_SOURCES" => "#{@work_dir}/cfgtest.c",
|
||||
"_TARGET" => "#{@work_dir}/cfgtest.exe",
|
||||
}
|
||||
command = BasicEnvironment.new.build_command("${LDCMD}", vars)
|
||||
_, _, status = log_and_test_command(command)
|
||||
status = 1
|
||||
check_libpath.each do |libpath|
|
||||
env = BasicEnvironment.new
|
||||
if libpath
|
||||
env["LIBPATH"] += Array(libpath)
|
||||
end
|
||||
command = env.build_command("${LDCMD}", vars)
|
||||
_, _, status = log_and_test_command(command)
|
||||
if status == 0
|
||||
if libpath
|
||||
store_append({"LIBPATH" => Array(libpath)}, options)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
if status == 0
|
||||
store_append({"LIBS" => [lib]}, options)
|
||||
end
|
||||
common_config_checks(status, options)
|
||||
complete(status, options)
|
||||
end
|
||||
|
||||
# Check for a executable program.
|
||||
def check_program(program, options = {})
|
||||
Ansi.write($stdout, "Checking for program '", :cyan, program, :reset, "'... ")
|
||||
path = Util.find_executable(program)
|
||||
common_config_checks(path ? 0 : 1, options.merge(success_message: path))
|
||||
complete(path ? 0 : 1, options.merge(success_message: path))
|
||||
end
|
||||
|
||||
# Execute a test command and log the result.
|
||||
#
|
||||
# @param command [Array<String>]
|
||||
# Command to execute.
|
||||
# @param options [Hash]
|
||||
# Optional arguments.
|
||||
# @option options [String] :stdin
|
||||
# Data to send to standard input stream of the executed command.
|
||||
#
|
||||
# @return [String, String, Process::Status]
|
||||
# stdout, stderr, status
|
||||
def log_and_test_command(command, options = {})
|
||||
begin
|
||||
@log_fh.puts("Command: #{command.join(" ")}")
|
||||
stdout, stderr, status = Open3.capture3(*command, stdin_data: options[:stdin])
|
||||
@log_fh.puts("Exit status: #{status.to_i}")
|
||||
@log_fh.write(stdout)
|
||||
@log_fh.write(stderr)
|
||||
[stdout, stderr, status]
|
||||
rescue Errno::ENOENT
|
||||
["", "", 127]
|
||||
end
|
||||
end
|
||||
|
||||
# Store construction variables for merging into the Cache.
|
||||
#
|
||||
# @param vars [Hash]
|
||||
# Hash containing the variables to merge.
|
||||
# @param options [Hash]
|
||||
# Options.
|
||||
# @option options [String] :use
|
||||
# A 'use' name. If specified, the construction variables are only applied
|
||||
# to an Environment if the Environment is constructed with a matching
|
||||
# `:use` value.
|
||||
def store_merge(vars, options = {})
|
||||
store_vars = store_common(options)
|
||||
store_vars["merge"] ||= {}
|
||||
vars.each_pair do |key, value|
|
||||
store_vars["merge"][key] = value
|
||||
end
|
||||
end
|
||||
|
||||
# Store construction variables for appending into the Cache.
|
||||
#
|
||||
# @param vars [Hash]
|
||||
# Hash containing the variables to append.
|
||||
# @param options [Hash]
|
||||
# Options.
|
||||
# @option options [String] :use
|
||||
# A 'use' name. If specified, the construction variables are only applied
|
||||
# to an Environment if the Environment is constructed with a matching
|
||||
# `:use` value.
|
||||
def store_append(vars, options = {})
|
||||
store_vars = store_common(options)
|
||||
store_vars["append"] ||= {}
|
||||
vars.each_pair do |key, value|
|
||||
if store_vars["append"][key].is_a?(Array) and value.is_a?(Array)
|
||||
store_vars["append"][key] += value
|
||||
else
|
||||
store_vars["append"][key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Store flags to be parsed into the Cache.
|
||||
#
|
||||
# @param flags [String]
|
||||
# String containing the flags to parse.
|
||||
# @param options [Hash]
|
||||
# Options.
|
||||
# @option options [String] :use
|
||||
# A 'use' name. If specified, the construction variables are only applied
|
||||
# to an Environment if the Environment is constructed with a matching
|
||||
# `:use` value.
|
||||
def store_parse(flags, options = {})
|
||||
store_vars = store_common(options)
|
||||
store_vars["parse"] ||= []
|
||||
store_vars["parse"] << flags
|
||||
end
|
||||
|
||||
# Perform processing common to several configure checks.
|
||||
#
|
||||
# @param status [Process::Status, Integer]
|
||||
# Process exit code. 0 for success, non-zero for error.
|
||||
# @param options [Hash]
|
||||
# Common check options.
|
||||
# @option options [Boolean] :fail
|
||||
# Whether to fail configuration if the requested item is not found.
|
||||
# This defaults to true if the :set_define option is not specified,
|
||||
# otherwise defaults to false if :set_define option is specified.
|
||||
# @option options [String] :set_define
|
||||
# A define to set (in CPPDEFINES) if the requested item is found.
|
||||
# @option options [String] :success_message
|
||||
# Message to print on success (default "found").
|
||||
def complete(status, options)
|
||||
success_message = options[:success_message] || "found"
|
||||
fail_message = options[:fail_message] || "not found"
|
||||
if status == 0
|
||||
Ansi.write($stdout, :green, "#{success_message}\n")
|
||||
if options[:set_define]
|
||||
store_append("CPPDEFINES" => [options[:set_define]])
|
||||
end
|
||||
else
|
||||
should_fail =
|
||||
if options.has_key?(:fail)
|
||||
options[:fail]
|
||||
else
|
||||
!options[:set_define]
|
||||
end
|
||||
if should_fail
|
||||
Ansi.write($stdout, :red, "#{fail_message}\n")
|
||||
raise ConfigureFailure.new
|
||||
else
|
||||
Ansi.write($stdout, :yellow, "#{fail_message}\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
@@ -309,7 +486,12 @@ module Rscons
|
||||
"DC" => dc,
|
||||
"DCCMD" => env["DCCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
|
||||
"LDCMD" => env["LDCMD"].map {|e| if e == "-o"; "-of"; else; e; end},
|
||||
"DDEPGEN" => ["-deps=${_DEPFILE}"],
|
||||
}
|
||||
if RUBY_PLATFORM =~ /mingw/
|
||||
# ldc2 on Windows expect an object file suffix of .obj.
|
||||
merge["OBJSUFFIX"] = %w[.obj]
|
||||
end
|
||||
end
|
||||
_, _, status = log_and_test_command(command)
|
||||
if status == 0
|
||||
@@ -322,64 +504,6 @@ module Rscons
|
||||
end
|
||||
end
|
||||
|
||||
# Execute a test command and log the result.
|
||||
def log_and_test_command(command)
|
||||
begin
|
||||
@log_fh.puts("Command: #{command.join(" ")}")
|
||||
stdout, stderr, status = Open3.capture3(*command)
|
||||
@log_fh.puts("Exit status: #{status.to_i}")
|
||||
@log_fh.write(stdout)
|
||||
@log_fh.write(stderr)
|
||||
[stdout, stderr, status]
|
||||
rescue Errno::ENOENT
|
||||
["", "", 127]
|
||||
end
|
||||
end
|
||||
|
||||
# Store construction variables for merging into the Cache.
|
||||
#
|
||||
# @param vars [Hash]
|
||||
# Hash containing the variables to merge.
|
||||
# @param options [Hash]
|
||||
# Options.
|
||||
def store_merge(vars, options = {})
|
||||
store_vars = store_common(options)
|
||||
store_vars["merge"] ||= {}
|
||||
vars.each_pair do |key, value|
|
||||
store_vars["merge"][key] = value
|
||||
end
|
||||
end
|
||||
|
||||
# Store construction variables for appending into the Cache.
|
||||
#
|
||||
# @param vars [Hash]
|
||||
# Hash containing the variables to append.
|
||||
# @param options [Hash]
|
||||
# Options.
|
||||
def store_append(vars, options = {})
|
||||
store_vars = store_common(options)
|
||||
store_vars["append"] ||= {}
|
||||
vars.each_pair do |key, value|
|
||||
if store_vars["append"][key].is_a?(Array) and value.is_a?(Array)
|
||||
store_vars["append"][key] += value
|
||||
else
|
||||
store_vars["append"][key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Store flags to be parsed into the Cache.
|
||||
#
|
||||
# @param flags [String]
|
||||
# String containing the flags to parse.
|
||||
# @param options [Hash]
|
||||
# Options.
|
||||
def store_parse(flags, options = {})
|
||||
store_vars = store_common(options)
|
||||
store_vars["parse"] ||= []
|
||||
store_vars["parse"] << flags
|
||||
end
|
||||
|
||||
# Common functionality for all store methods.
|
||||
#
|
||||
# @param options [Hash]
|
||||
@@ -403,34 +527,5 @@ module Rscons
|
||||
end
|
||||
end
|
||||
|
||||
# Perform processing common to several configure checks.
|
||||
#
|
||||
# @param status [Process::Status, Integer]
|
||||
# Process exit code.
|
||||
# @param options [Hash]
|
||||
# Common check options.
|
||||
# @option options [Boolean] :fail
|
||||
# Whether to fail configuration if the requested item is not found.
|
||||
# @option options [String] :set_define
|
||||
# A define to set (in CPPDEFINES) if the requested item is found.
|
||||
# @option options [String] :success_message
|
||||
# Message to print on success (default "found").
|
||||
def common_config_checks(status, options)
|
||||
success_message = options[:success_message] || "found"
|
||||
if status == 0
|
||||
Ansi.write($stdout, :green, "#{success_message}\n")
|
||||
if options[:set_define]
|
||||
store_append("CPPDEFINES" => [options[:set_define]])
|
||||
end
|
||||
else
|
||||
if options.has_key?(:fail) and not options[:fail]
|
||||
Ansi.write($stdout, :yellow, "not found\n")
|
||||
else
|
||||
Ansi.write($stdout, :red, "not found\n")
|
||||
raise ConfigureFailure.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -59,6 +59,9 @@ module Rscons
|
||||
# :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.
|
||||
@@ -248,7 +251,7 @@ module Rscons
|
||||
if extra_path = builder_class.extra_path
|
||||
extra_path = "/#{extra_path}"
|
||||
end
|
||||
"#{@build_root}#{extra_path}/#{Util.make_relative_path(Rscons.set_suffix(source_fname, suffix))}".gsub("\\", "/")
|
||||
"#{@build_root}#{extra_path}/#{Util.make_relative_path("#{source_fname}#{suffix}")}".gsub("\\", "/")
|
||||
end
|
||||
|
||||
# Build all build targets specified in the Environment.
|
||||
@@ -284,7 +287,7 @@ module Rscons
|
||||
unless @process_failures.empty?
|
||||
msg = @process_failures.join("\n")
|
||||
if Cache.instance["failed_commands"].size > 0
|
||||
msg += "\nRun `#{$0} -F` to see the failed command(s)."
|
||||
msg += "\nUse -F to view the failed command log from the previous build operation"
|
||||
end
|
||||
raise BuildError.new(msg)
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@ module Rscons
|
||||
# The Script class encapsulates the state of a build script.
|
||||
class Script
|
||||
|
||||
# DSL available to the Rsconscript.
|
||||
class Dsl
|
||||
# Create a Dsl.
|
||||
def initialize(script)
|
||||
@@ -57,6 +58,7 @@ module Rscons
|
||||
end
|
||||
end
|
||||
|
||||
# DSL available to the 'configure' block.
|
||||
class ConfigureDsl
|
||||
# Create a ConfigureDsl.
|
||||
#
|
||||
@@ -81,6 +83,19 @@ module Rscons
|
||||
@configure_op.__send__(method_name, *args)
|
||||
end
|
||||
end
|
||||
|
||||
# Perform a custom configuration check.
|
||||
#
|
||||
# @param message [String]
|
||||
# Custom configuration check message (e.g. "Checking for foo").
|
||||
# rscons will add "... " to the end of the message.
|
||||
# @yieldparam configure_op [ConfigureOp]
|
||||
# {ConfigureOp} object.
|
||||
# @return [void]
|
||||
def custom_check(message, &block)
|
||||
$stdout.write(message + "... ")
|
||||
block[@configure_op]
|
||||
end
|
||||
end
|
||||
|
||||
# @return [String, nil]
|
||||
|
||||
+20
-13
@@ -1,4 +1,5 @@
|
||||
module Rscons
|
||||
# A collection of stand-alone utility methods.
|
||||
module Util
|
||||
class << self
|
||||
|
||||
@@ -159,7 +160,7 @@ module Rscons
|
||||
end
|
||||
end
|
||||
|
||||
# Parse dependencies from a Makefile.
|
||||
# Parse dependencies from a Makefile or ldc2 dependency file.
|
||||
#
|
||||
# This method is used internally by Rscons builders.
|
||||
#
|
||||
@@ -168,7 +169,7 @@ module Rscons
|
||||
#
|
||||
# @return [Array<String>]
|
||||
# Paths of dependency files.
|
||||
def parse_makefile_deps(mf_fname)
|
||||
def parse_dependency_file(mf_fname)
|
||||
deps = []
|
||||
buildup = ''
|
||||
File.read(mf_fname).each_line do |line|
|
||||
@@ -176,7 +177,11 @@ module Rscons
|
||||
buildup += ' ' + $1
|
||||
else
|
||||
buildup += ' ' + line
|
||||
if buildup =~ /^.*: (.*)$/
|
||||
if buildup =~ /^[^:]+\(\S+\)\s*:.*?:[^:]+\((\S+)\)/
|
||||
# ldc2-style dependency line
|
||||
deps << $1
|
||||
elsif buildup =~ /^.*: (.*)$/
|
||||
# Makefile-style dependency line
|
||||
mf_deps = $1
|
||||
deps += mf_deps.split(' ').map(&:strip)
|
||||
end
|
||||
@@ -199,16 +204,18 @@ module Rscons
|
||||
File.file?(path) and File.executable?(path)
|
||||
end
|
||||
if RbConfig::CONFIG["host_os"] =~ /mswin|windows|mingw/i
|
||||
executable = executable.downcase
|
||||
dir_entries = Dir.entries(path_entry)
|
||||
dir_entries.find do |entry|
|
||||
path = "#{path_entry}/#{entry}"
|
||||
entry = entry.downcase
|
||||
if ((entry == executable) or
|
||||
(entry == "#{executable}.exe") or
|
||||
(entry == "#{executable}.com") or
|
||||
(entry == "#{executable}.bat")) and is_executable[path]
|
||||
return path
|
||||
if File.directory?(path_entry)
|
||||
executable = executable.downcase
|
||||
dir_entries = Dir.entries(path_entry)
|
||||
dir_entries.find do |entry|
|
||||
path = "#{path_entry}/#{entry}"
|
||||
entry = entry.downcase
|
||||
if ((entry == executable) or
|
||||
(entry == "#{executable}.exe") or
|
||||
(entry == "#{executable}.com") or
|
||||
(entry == "#{executable}.bat")) and is_executable[path]
|
||||
return path
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module Rscons
|
||||
# Project version.
|
||||
VERSION = "2.0.0beta1"
|
||||
VERSION = "2.0.2"
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>RScons User Guide<%= subpage_title %> - Version <%= Rscons::VERSION %></title>
|
||||
<title>Rscons User Guide<%= subpage_title %> - Version <%= Rscons::VERSION %></title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #CCC;
|
||||
@@ -31,6 +31,11 @@
|
||||
.separator {
|
||||
height: 2em;
|
||||
}
|
||||
.img_block_center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.page_nav {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
|
||||
+7
-5
@@ -59,9 +59,10 @@ combined_file.each do |line|
|
||||
end
|
||||
|
||||
require "zlib"
|
||||
require "base64"
|
||||
compressed_script = Zlib::Deflate.deflate(stripped_comments.join)
|
||||
escaped_compressed_script = compressed_script.gsub("#", "#1").gsub("\n", "#2").gsub("\r", "#3").gsub("\0", "#4")
|
||||
hash = Digest::MD5.hexdigest(escaped_compressed_script)
|
||||
encoded_compressed_script = Base64.encode64(compressed_script).gsub("\n", "")
|
||||
hash = Digest::MD5.hexdigest(encoded_compressed_script)
|
||||
|
||||
FileUtils.mkdir_p(DIST)
|
||||
File.open("#{DIST}/#{PROG_NAME}", "wb", 0755) do |fh|
|
||||
@@ -70,9 +71,10 @@ File.open("#{DIST}/#{PROG_NAME}", "wb", 0755) do |fh|
|
||||
script = File.join(File.dirname(__FILE__), ".rscons-#{VERSION}-#{hash}.rb")
|
||||
unless File.exists?(script)
|
||||
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
|
||||
escaped_compressed = $1
|
||||
unescaped_compressed = escaped_compressed.gsub("#4", "\\0").gsub("#3", "\\r").gsub("#2", "\\n").gsub("#1", "#")
|
||||
require "zlib"
|
||||
require "base64"
|
||||
encoded_compressed = $1
|
||||
unescaped_compressed = Base64.decode64(encoded_compressed)
|
||||
inflated = Zlib::Inflate.inflate(unescaped_compressed)
|
||||
File.open(script, "wb") do |fh|
|
||||
fh.write(inflated)
|
||||
@@ -85,6 +87,6 @@ load script
|
||||
if __FILE__ == $0
|
||||
Rscons::Cli.run(ARGV)
|
||||
end
|
||||
#==>#{escaped_compressed_script}
|
||||
#==>#{encoded_compressed_script}
|
||||
EOF
|
||||
end
|
||||
+14
-1
@@ -59,6 +59,8 @@ class Generator
|
||||
line = @lines.slice!(0)
|
||||
if line =~ /^```(.*)$/
|
||||
@sections.last.append(gather_code_section($1))
|
||||
elsif line.chomp == "${remove}"
|
||||
remove_section
|
||||
elsif line =~ /^(#+)(>)?\s*(.*)$/
|
||||
level_text, new_page_text, title_text = $1, $2, $3
|
||||
level = $1.size
|
||||
@@ -152,7 +154,8 @@ class Generator
|
||||
end
|
||||
|
||||
def render_toc
|
||||
toc_content = %[<h1>Table of Contents</h1>\n]
|
||||
toc_content = %[<img class="img_block_center" src="rscons_logo_1000.png" />]
|
||||
toc_content += %[<h1>Table of Contents</h1>\n]
|
||||
@sections.each do |section|
|
||||
indent = section.number.split(".").size - 1
|
||||
toc_content += %[<span style="padding-left: #{4 * indent}ex;">]
|
||||
@@ -196,6 +199,15 @@ class Generator
|
||||
end
|
||||
end
|
||||
|
||||
def remove_section
|
||||
loop do
|
||||
line = @lines.slice!(0)
|
||||
if line.chomp == "${/remove}"
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_next_section_number(level)
|
||||
if @current_section_number.size == level - 1
|
||||
@current_section_number << 1
|
||||
@@ -212,5 +224,6 @@ end
|
||||
input = load_file("doc/user_guide.md")
|
||||
FileUtils.rm_rf("gen/user_guide")
|
||||
FileUtils.mkdir_p("gen/user_guide")
|
||||
FileUtils.cp("img/rscons_logo_1000.png", "gen/user_guide")
|
||||
Generator.new(input, "gen/user_guide/user_guide.html", false)
|
||||
Generator.new(input, "gen/user_guide", true)
|
||||
+294
-90
@@ -65,6 +65,9 @@ describe Rscons do
|
||||
|
||||
def create_exe(exe_name, contents)
|
||||
exe_file = "#{@build_test_run_dir}/_bin/#{exe_name}"
|
||||
if RUBY_PLATFORM =~ /mingw/
|
||||
exe_file += ".bat"
|
||||
end
|
||||
File.open(exe_file, "wb") do |fh|
|
||||
fh.puts("#!/bin/sh")
|
||||
fh.puts(contents)
|
||||
@@ -142,7 +145,11 @@ EOF
|
||||
stdout, stderr, status = nil, nil, nil
|
||||
Bundler.with_clean_env do
|
||||
env = ENV.to_h
|
||||
env["PATH"] = "#{@build_test_run_dir}/_bin#{File::PATH_SEPARATOR}#{env["PATH"]}"
|
||||
path = ["#{@build_test_run_dir}/_bin", "#{env["PATH"]}"]
|
||||
if options[:path]
|
||||
path = Array(options[:path]) + path
|
||||
end
|
||||
env["PATH"] = path.join(File::PATH_SEPARATOR)
|
||||
stdout, stderr, status = Open3.capture3(env, *command)
|
||||
File.open("#{@build_test_run_dir}/.stdout", "wb") do |fh|
|
||||
fh.write(stdout)
|
||||
@@ -188,7 +195,7 @@ EOF
|
||||
test_dir('simple')
|
||||
result = run_rscons
|
||||
expect(result.stderr).to eq ""
|
||||
expect(File.exists?('build/e.1/simple.o')).to be_truthy
|
||||
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
|
||||
expect(`./simple.exe`).to eq "This is a simple C program\n"
|
||||
end
|
||||
|
||||
@@ -205,8 +212,8 @@ EOF
|
||||
result = run_rscons(rsconscript: "command.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -c -o build/e.1/simple.o -MMD -MF build/e.1/simple.mf simple.c},
|
||||
%r{gcc -o simple.exe build/e.1/simple.o},
|
||||
%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},
|
||||
])
|
||||
end
|
||||
|
||||
@@ -224,7 +231,7 @@ EOF
|
||||
test_dir('header')
|
||||
result = run_rscons
|
||||
expect(result.stderr).to eq ""
|
||||
expect(File.exists?('build/e.1/header.o')).to be_truthy
|
||||
expect(File.exists?('build/e.1/header.c.o')).to be_truthy
|
||||
expect(`./header.exe`).to eq "The value is 2\n"
|
||||
end
|
||||
|
||||
@@ -274,13 +281,13 @@ EOF
|
||||
result = run_rscons(rsconscript: "command.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -c -o build/e.1/simple.o -MMD -MF build/e.1/simple.mf simple.c},
|
||||
%r{gcc -o simple.exe build/e.1/simple.o},
|
||||
%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},
|
||||
])
|
||||
result = run_rscons(rsconscript: "link_flag_change.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -o simple.exe build/e.1/simple.o -Llibdir},
|
||||
%r{gcc -o simple.exe build/e.1/simple.c.o -Llibdir},
|
||||
])
|
||||
end
|
||||
|
||||
@@ -310,9 +317,9 @@ EOF
|
||||
result = run_rscons(rsconscript: "carat.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -c -o build/e.1/one.o -MMD -MF build/e.1/one.mf -Isrc -Isrc/one -Isrc/two build/e.1/one.c},
|
||||
%r{gcc -c -o build/e.1/src/two/two.o -MMD -MF build/e.1/src/two/two.mf -Isrc -Isrc/one -Isrc/two src/two/two.c},
|
||||
%r{gcc -o program.exe build/e.1/src/two/two.o build/e.1/one.o},
|
||||
%r{gcc -c -o build/e.1/one.o -MMD -MF build/e.1/one.o.mf -Isrc -Isrc/one -Isrc/two build/e.1/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 -Isrc/one -Isrc/two src/two/two.c},
|
||||
%r{gcc -o program.exe build/e.1/src/two/two.c.o build/e.1/one.o},
|
||||
])
|
||||
end
|
||||
|
||||
@@ -330,15 +337,29 @@ EOF
|
||||
expect(result.stderr).to match /Could not find a registered build target "foo"/
|
||||
end
|
||||
|
||||
it "allows replacing a running executable when performing an 'install' operation" do
|
||||
test_dir("install_running_exe")
|
||||
result = run_rscons(op: "install")
|
||||
expect(result.stderr).to eq ""
|
||||
fcontents = File.read("program.c", mode: "rb")
|
||||
File.open("program.c", "wb") do |fh|
|
||||
fh.write(fcontents.sub(/2/, '3'))
|
||||
end
|
||||
pid = Process.spawn("install/program.exe")
|
||||
result = run_rscons(op: "install")
|
||||
expect(result.stderr).to eq ""
|
||||
Process.wait(pid)
|
||||
end
|
||||
|
||||
context "clean operation" do
|
||||
it 'cleans built files' do
|
||||
test_dir("simple")
|
||||
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.o')).to be_truthy
|
||||
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
|
||||
result = run_rscons(op: %w[clean])
|
||||
expect(File.exists?('build/e.1/simple.o')).to be_falsey
|
||||
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
|
||||
@@ -349,7 +370,7 @@ 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.o')).to be_truthy
|
||||
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
|
||||
File.open('build/e.1/dum', 'w') { |fh| fh.puts "dum" }
|
||||
result = run_rscons(op: %w[clean])
|
||||
expect(File.exists?('build/e.1')).to be_truthy
|
||||
@@ -366,12 +387,12 @@ EOF
|
||||
result = run_rscons(rsconscript: "install.rb", op: %W[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.o")).to be_truthy
|
||||
expect(File.exists?("build/e.1/src/one/one.c.o")).to be_truthy
|
||||
|
||||
result = run_rscons(rsconscript: "install.rb", op: %W[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.o")).to be_falsey
|
||||
expect(File.exists?("build/e.1/src/one/one.c.o")).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
@@ -388,7 +409,7 @@ EOF
|
||||
result = run_rscons(rsconscript: "install.rb", op: %W[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.o")).to be_falsey
|
||||
expect(File.exists?("build/e.1/src/one/one.c.o")).to be_falsey
|
||||
|
||||
result = run_rscons(rsconscript: "install.rb", op: %W[uninstall -v])
|
||||
expect(result.stderr).to eq ""
|
||||
@@ -470,10 +491,10 @@ EOF
|
||||
result = run_rscons
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -c -o build/e.1/src/program.o -MMD -MF build/e.1/src/program.mf '-DSTRING="Debug Version"' -O2 src/program.c},
|
||||
%r{gcc -o program-debug.exe build/e.1/src/program.o},
|
||||
%r{gcc -c -o build/e.2/src/program.o -MMD -MF build/e.2/src/program.mf '-DSTRING="Release Version"' -O2 src/program.c},
|
||||
%r{gcc -o program-release.exe build/e.2/src/program.o},
|
||||
%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},
|
||||
])
|
||||
end
|
||||
|
||||
@@ -482,12 +503,12 @@ EOF
|
||||
result = run_rscons(rsconscript: "clone_all.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -c -o build/e.1/src/program.o -MMD -MF build/e.1/src/program.mf -DSTRING="Hello" -O2 src/program.c},
|
||||
%r{post build/e.1/src/program.o},
|
||||
%r{gcc -o program.exe build/e.1/src/program.o},
|
||||
%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{post program.exe},
|
||||
%r{post build/e.2/src/program.o},
|
||||
%r{gcc -o program2.exe build/e.2/src/program.o},
|
||||
%r{post build/e.2/src/program.c.o},
|
||||
%r{gcc -o program2.exe build/e.2/src/program.c.o},
|
||||
%r{post program2.exe},
|
||||
])
|
||||
end
|
||||
@@ -496,7 +517,7 @@ EOF
|
||||
test_dir('simple_cc')
|
||||
result = run_rscons
|
||||
expect(result.stderr).to eq ""
|
||||
expect(File.exists?('build/e.1/simple.o')).to be_truthy
|
||||
expect(File.exists?('build/e.1/simple.cc.o')).to be_truthy
|
||||
expect(`./simple.exe`).to eq "This is a simple C++ program\n"
|
||||
end
|
||||
|
||||
@@ -513,9 +534,9 @@ EOF
|
||||
result = run_rscons
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -c -o one.o -MMD -MF one.mf -DONE one.c},
|
||||
%r{gcc -c -o build/e.1/two.o -MMD -MF build/e.1/two.mf two.c},
|
||||
%r{gcc -o two_sources.exe one.o build/e.1/two.o},
|
||||
%r{gcc -c -o one.o -MMD -MF 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},
|
||||
])
|
||||
expect(File.exists?("two_sources.exe")).to be_truthy
|
||||
expect(`./two_sources.exe`).to eq "This is a C program with two sources.\n"
|
||||
@@ -526,14 +547,14 @@ EOF
|
||||
result = run_rscons
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -c -o build/e.1/one.o -MMD -MF build/e.1/one.mf -Dmake_lib one.c},
|
||||
%r{gcc -c -o build/e.1/two.o -MMD -MF build/e.1/two.mf -Dmake_lib two.c},
|
||||
%r{ar rcs lib.a build/e.1/one.o build/e.1/two.o},
|
||||
%r{gcc -c -o build/e.1/three.o -MMD -MF build/e.1/three.mf three.c},
|
||||
%r{gcc -o library.exe lib.a build/e.1/three.o},
|
||||
%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{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 three.c},
|
||||
%r{gcc -o library.exe lib.a build/e.1/three.c.o},
|
||||
])
|
||||
expect(File.exists?("library.exe")).to be_truthy
|
||||
expect(`ar t lib.a`).to eq "one.o\ntwo.o\n"
|
||||
expect(`ar t lib.a`).to eq "one.c.o\ntwo.c.o\n"
|
||||
end
|
||||
|
||||
it 'supports build hooks to override construction variables' do
|
||||
@@ -541,9 +562,9 @@ EOF
|
||||
result = run_rscons(rsconscript: "build_hooks.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -c -o build/e.1/src/one/one.o -MMD -MF build/e.1/src/one/one.mf -Isrc/one -Isrc/two -O1 src/one/one.c},
|
||||
%r{gcc -c -o build/e.1/src/two/two.o -MMD -MF build/e.1/src/two/two.mf -Isrc/one -Isrc/two -O2 src/two/two.c},
|
||||
%r{gcc -o build_hook.exe build/e.1/src/one/one.o build/e.1/src/two/two.o},
|
||||
%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},
|
||||
])
|
||||
expect(`./build_hook.exe`).to eq "Hello from two()\n"
|
||||
end
|
||||
@@ -553,8 +574,8 @@ EOF
|
||||
result = run_rscons(rsconscript: "build_hooks_override_vars.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -c -o one.o -MMD -MF one.mf -Isrc -Isrc/one -Isrc/two -O1 src/two/two.c},
|
||||
%r{gcc -c -o two.o -MMD -MF two.mf -Isrc -Isrc/one -Isrc/two -O2 src/two/two.c},
|
||||
%r{gcc -c -o one.o -MMD -MF one.o.mf -Isrc -Isrc/one -Isrc/two -O1 src/two/two.c},
|
||||
%r{gcc -c -o two.o -MMD -MF 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
|
||||
@@ -570,7 +591,7 @@ EOF
|
||||
%r{Compiling simple.c},
|
||||
%r{Linking simple.exe},
|
||||
])
|
||||
expect(File.exists?('build/e.1/simple.o')).to be_truthy
|
||||
expect(File.exists?('build/e.1/simple.c.o')).to be_truthy
|
||||
expect(`./simple.exe`).to eq "This is a simple C program\n"
|
||||
|
||||
File.open("program.ld", "w") {|fh| fh.puts("2")}
|
||||
@@ -588,18 +609,51 @@ EOF
|
||||
expect(result.stdout).to eq ""
|
||||
end
|
||||
|
||||
unless ENV["omit_gdc_tests"]
|
||||
it "supports building D sources" do
|
||||
test_dir("d")
|
||||
result = run_rscons
|
||||
expect(result.stderr).to eq ""
|
||||
slines = lines(result.stdout)
|
||||
verify_lines(slines, [%r{gdc -c -o build/e.1/main.o -MMD -MF build/e.1/main.mf main.d}])
|
||||
verify_lines(slines, [%r{gdc -c -o build/e.1/mod.o -MMD -MF build/e.1/mod.mf mod.d}])
|
||||
verify_lines(slines, [%r{gdc -o hello-d.exe build/e.1/main.o build/e.1/mod.o}])
|
||||
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
|
||||
end
|
||||
it "supports building D sources with gdc" do
|
||||
test_dir("d")
|
||||
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}])
|
||||
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
|
||||
end
|
||||
|
||||
it "supports building D sources with ldc2" do
|
||||
test_dir("d")
|
||||
result = run_rscons(rsconscript: "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.mf main.d}])
|
||||
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o.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)?}])
|
||||
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 42!"
|
||||
end
|
||||
|
||||
it "rebuilds D modules with ldc2 when deep dependencies change" do
|
||||
test_dir("d")
|
||||
result = run_rscons(rsconscript: "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.mf main.d}])
|
||||
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o.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)?}])
|
||||
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|
|
||||
fh.write(contents)
|
||||
end
|
||||
result = run_rscons(rsconscript: "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.mf main.d}])
|
||||
verify_lines(slines, [%r{ldc2 -c -of build/e.1/mod.d.o(bj)? -deps=build/e.1/mod.d.o.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)?}])
|
||||
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 33!"
|
||||
end
|
||||
|
||||
unless ENV["omit_gdc_tests"]
|
||||
it "links with the D linker when object files were built from D sources" do
|
||||
test_dir("d")
|
||||
result = run_rscons(rsconscript: "link_objects.rb")
|
||||
@@ -614,18 +668,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.o -MMD -MF build/e.1/main.mf main.d}])
|
||||
verify_lines(slines, [%r{gdc -c -o build/e.1/mod.o -MMD -MF build/e.1/mod.mf mod.d}])
|
||||
verify_lines(slines, [%r{gdc -o hello-d.exe build/e.1/main.o build/e.1/mod.o}])
|
||||
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}])
|
||||
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.o -MMD -MF build/e.1/main.mf main.d}])
|
||||
verify_lines(slines, [%r{gdc -c -o build/e.1/mod.o -MMD -MF build/e.1/mod.mf mod.d}])
|
||||
verify_lines(slines, [%r{gdc -o hello-d.exe build/e.1/main.o build/e.1/mod.o}])
|
||||
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}])
|
||||
expect(`./hello-d.exe`.rstrip).to eq "Hello from D, value is 33!"
|
||||
end
|
||||
|
||||
@@ -633,11 +687,7 @@ EOF
|
||||
test_dir("shared_library")
|
||||
|
||||
result = run_rscons(rsconscript: "shared_library_d.rb")
|
||||
# Currently gdc produces an error while trying to build the shared
|
||||
# library. Since this isn't really an rscons problem, I'm commenting out
|
||||
# this check. I'm not sure what I want to do about D support at this
|
||||
# point anyway...
|
||||
#expect(result.stderr).to eq ""
|
||||
expect(result.stderr).to eq ""
|
||||
slines = lines(result.stdout)
|
||||
if RUBY_PLATFORM =~ /mingw/
|
||||
verify_lines(slines, [%r{Linking mine.dll}])
|
||||
@@ -705,8 +755,8 @@ EOF
|
||||
test_dir("simple")
|
||||
result = run_rscons(rsconscript: "register_target_in_build_hook.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(File.exists?("build/e.1/simple.o")).to be_truthy
|
||||
expect(File.exists?("build/e.1/simple.o.txt")).to be_truthy
|
||||
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(`./simple.exe`).to eq "This is a simple C program\n"
|
||||
end
|
||||
|
||||
@@ -715,8 +765,8 @@ EOF
|
||||
File.open("other.cccc", "w") {|fh| fh.puts}
|
||||
result = run_rscons(rsconscript: "cxxsuffix.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(File.exists?("build/e.1/simple.o")).to be_truthy
|
||||
expect(File.exists?("build/e.1/other.o")).to be_truthy
|
||||
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(`./simple.exe`).to eq "This is a simple C++ program\n"
|
||||
end
|
||||
|
||||
@@ -725,8 +775,8 @@ EOF
|
||||
FileUtils.mv("src/one/one.c", "src/one/one.yargh")
|
||||
result = run_rscons(rsconscript: "csuffix.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(File.exists?("build/e.1/src/one/one.o")).to be_truthy
|
||||
expect(File.exists?("build/e.1/src/two/two.o")).to be_truthy
|
||||
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(`./program.exe`).to eq "Hello from two()\n"
|
||||
end
|
||||
|
||||
@@ -798,7 +848,7 @@ EOF
|
||||
test_dir("simple")
|
||||
result = run_rscons(rsconscript: "cvar_array.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(File.exists?("build/e.1/simple.o")).to be_truthy
|
||||
expect(File.exists?("build/e.1/simple.c.o")).to be_truthy
|
||||
expect(`./simple.exe`).to eq "This is a simple C program\n"
|
||||
end
|
||||
|
||||
@@ -880,7 +930,7 @@ EOF
|
||||
result = run_rscons(rsconscript: "absolute_source_path.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
slines = lines(result.stdout)
|
||||
verify_lines(slines, [%r{build/e.1/.*/abs\.o$}])
|
||||
verify_lines(slines, [%r{build/e.1/.*/abs\.c.o$}])
|
||||
verify_lines(slines, [%r{\babs.exe\b}])
|
||||
end
|
||||
|
||||
@@ -998,7 +1048,7 @@ EOF
|
||||
|
||||
result = run_rscons
|
||||
expect(result.stderr).to match /Failed to build/
|
||||
expect(result.stderr).to match /^Run.*-F.*to see the failed command/
|
||||
expect(result.stderr).to match /^Use.*-F.*to view the failed command log/
|
||||
expect(result.status).to_not eq 0
|
||||
|
||||
result = run_rscons(rscons_args: %w[-F])
|
||||
@@ -1395,6 +1445,18 @@ EOF
|
||||
expect(result.stdout).to eq ""
|
||||
end
|
||||
|
||||
it "supports building multiple object files from sources with the same pathname and basename" do
|
||||
test_dir "multiple_basename"
|
||||
result = run_rscons
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.status).to eq 0
|
||||
expect(File.exist?("foo.exe")).to be_truthy
|
||||
result = run_rscons
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stdout).to eq ""
|
||||
expect(result.status).to eq 0
|
||||
end
|
||||
|
||||
context "debugging" do
|
||||
it "prints a message when the target does not exist" do
|
||||
test_dir("simple")
|
||||
@@ -1488,7 +1550,7 @@ EOF
|
||||
result = run_rscons(rsconscript: "override_depfilesuffix.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [
|
||||
%r{gcc -c -o simple.o -MMD -MF simple.deppy simple.c},
|
||||
%r{gcc -c -o simple.o -MMD -MF simple.o.deppy simple.c},
|
||||
])
|
||||
end
|
||||
|
||||
@@ -1512,7 +1574,7 @@ EOF
|
||||
test_dir("library")
|
||||
result = run_rscons(rsconscript: "override_arcmd.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
verify_lines(lines(result.stdout), [%r{ar rcf lib.a build/e.1/one.o build/e.1/three.o build/e.1/two.o}])
|
||||
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}])
|
||||
end
|
||||
|
||||
it "allows passing object files as sources" do
|
||||
@@ -1542,7 +1604,7 @@ EOF
|
||||
test_dir "shared_library"
|
||||
result = run_rscons(rsconscript: "shared_library_from_object.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(File.exists?("one.o"))
|
||||
expect(File.exists?("one.c.o"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1675,7 +1737,7 @@ EOF
|
||||
create_exe "gcc", "exit 1"
|
||||
create_exe "clang", "exit 1"
|
||||
result = run_rscons(rsconscript: rsconscript, op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stdout).to match /Checking for C compiler\.\.\. not found/
|
||||
end
|
||||
@@ -1718,7 +1780,7 @@ EOF
|
||||
create_exe "g++", "exit 1"
|
||||
create_exe "clang++", "exit 1"
|
||||
result = run_rscons(rsconscript: rsconscript, op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. not found/
|
||||
end
|
||||
@@ -1761,7 +1823,7 @@ EOF
|
||||
create_exe "gdc", "exit 1"
|
||||
create_exe "ldc2", "exit 1"
|
||||
result = run_rscons(rsconscript: rsconscript, op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stdout).to match /Checking for D compiler\.\.\. not found/
|
||||
end
|
||||
@@ -1799,7 +1861,7 @@ EOF
|
||||
it "fails when the requested header is not found" do
|
||||
test_dir "configure"
|
||||
result = run_rscons(rsconscript: "check_c_header_failure.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stdout).to match /Checking for C header 'not___found\.h'... not found/
|
||||
end
|
||||
@@ -1835,6 +1897,21 @@ EOF
|
||||
expect(result.status).to eq 0
|
||||
expect(result.stdout).to_not match /-DHAVE_/
|
||||
end
|
||||
|
||||
it "modifies CPPPATH based on check_cpppath" do
|
||||
test_dir "configure"
|
||||
FileUtils.mkdir_p("usr1")
|
||||
FileUtils.mkdir_p("usr2")
|
||||
File.open("usr2/frobulous.h", "wb") do |fh|
|
||||
fh.puts("#define FOO 42")
|
||||
end
|
||||
result = run_rscons(rsconscript: "check_c_header_cpppath.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.status).to eq 0
|
||||
result = run_rscons(rsconscript: "check_c_header_cpppath.rb", rscons_args: %w[-v])
|
||||
expect(result.stdout).to_not match %r{-I./usr1}
|
||||
expect(result.stdout).to match %r{-I./usr2}
|
||||
end
|
||||
end
|
||||
|
||||
context "check_cxx_header" do
|
||||
@@ -1849,7 +1926,7 @@ EOF
|
||||
it "fails when the requested header is not found" do
|
||||
test_dir "configure"
|
||||
result = run_rscons(rsconscript: "check_cxx_header_failure.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stdout).to match /Checking for C\+\+ header 'not___found\.h'... not found/
|
||||
end
|
||||
@@ -1861,6 +1938,21 @@ EOF
|
||||
expect(result.status).to eq 0
|
||||
expect(result.stdout).to match /Checking for C\+\+ header 'not___found\.h'... not found/
|
||||
end
|
||||
|
||||
it "modifies CPPPATH based on check_cpppath" do
|
||||
test_dir "configure"
|
||||
FileUtils.mkdir_p("usr1")
|
||||
FileUtils.mkdir_p("usr2")
|
||||
File.open("usr2/frobulous.h", "wb") do |fh|
|
||||
fh.puts("#define FOO 42")
|
||||
end
|
||||
result = run_rscons(rsconscript: "check_cxx_header_cpppath.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.status).to eq 0
|
||||
result = run_rscons(rsconscript: "check_cxx_header_cpppath.rb", rscons_args: %w[-v])
|
||||
expect(result.stdout).to_not match %r{-I./usr1}
|
||||
expect(result.stdout).to match %r{-I./usr2}
|
||||
end
|
||||
end
|
||||
|
||||
context "check_d_import" do
|
||||
@@ -1875,7 +1967,7 @@ EOF
|
||||
it "fails when the requested import is not found" do
|
||||
test_dir "configure"
|
||||
result = run_rscons(rsconscript: "check_d_import_failure.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stdout).to match /Checking for D import 'not\.found'... not found/
|
||||
end
|
||||
@@ -1887,6 +1979,21 @@ EOF
|
||||
expect(result.status).to eq 0
|
||||
expect(result.stdout).to match /Checking for D import 'not\.found'... not found/
|
||||
end
|
||||
|
||||
it "modifies D_IMPORT_PATH based on check_d_import_path" do
|
||||
test_dir "configure"
|
||||
FileUtils.mkdir_p("usr1")
|
||||
FileUtils.mkdir_p("usr2")
|
||||
File.open("usr2/frobulous.d", "wb") do |fh|
|
||||
fh.puts("int foo = 42;")
|
||||
end
|
||||
result = run_rscons(rsconscript: "check_d_import_d_import_path.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.status).to eq 0
|
||||
result = run_rscons(rsconscript: "check_d_import_d_import_path.rb", rscons_args: %w[-v])
|
||||
expect(result.stdout).to_not match %r{-I./usr1}
|
||||
expect(result.stdout).to match %r{-I./usr2}
|
||||
end
|
||||
end
|
||||
|
||||
context "check_lib" do
|
||||
@@ -1901,7 +2008,7 @@ EOF
|
||||
it "fails when the requested library is not found" do
|
||||
test_dir "configure"
|
||||
result = run_rscons(rsconscript: "check_lib_failure.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stdout).to match /Checking for library 'mfoofoo'... not found/
|
||||
end
|
||||
@@ -1941,6 +2048,23 @@ EOF
|
||||
expect(result.stdout).to match /Checking for library 'm'... found/
|
||||
expect(result.stdout).to_not match /-lm/
|
||||
end
|
||||
|
||||
it "modifies LIBPATH based on check_libpath" do
|
||||
test_dir "configure"
|
||||
FileUtils.mkdir_p("usr1")
|
||||
FileUtils.mkdir_p("usr2")
|
||||
result = run_rscons(rsconscript: "check_lib_libpath1.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.status).to eq 0
|
||||
result = run_rscons(rsconscript: "check_lib_libpath2.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.status).to eq 0
|
||||
result = run_rscons(rsconscript: "check_lib_libpath2.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.status).to eq 0
|
||||
expect(result.stdout).to match %r{-L\./usr2}
|
||||
expect(result.stdout).to_not match %r{-L\./usr1}
|
||||
end
|
||||
end
|
||||
|
||||
context "check_program" do
|
||||
@@ -1952,10 +2076,20 @@ EOF
|
||||
expect(result.stdout).to match /Checking for program 'find'... .*find/
|
||||
end
|
||||
|
||||
context "with non-existent PATH entries" do
|
||||
it "succeeds when the requested program is found" do
|
||||
test_dir "configure"
|
||||
result = run_rscons(rsconscript: "check_program_success.rb", op: "configure", path: "/foo/bar")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.status).to eq 0
|
||||
expect(result.stdout).to match /Checking for program 'find'... .*find/
|
||||
end
|
||||
end
|
||||
|
||||
it "fails when the requested program is not found" do
|
||||
test_dir "configure"
|
||||
result = run_rscons(rsconscript: "check_program_failure.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stdout).to match /Checking for program 'program-that-is-not-found'... not found/
|
||||
end
|
||||
@@ -1987,7 +2121,7 @@ EOF
|
||||
it "fails when the configure program given does not exist" do
|
||||
test_dir "configure"
|
||||
result = run_rscons(rsconscript: "check_cfg.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stdout).to match /Checking 'my-config'\.\.\. not found/
|
||||
end
|
||||
@@ -2024,6 +2158,74 @@ EOF
|
||||
end
|
||||
end
|
||||
|
||||
context "custom_check" do
|
||||
context "when running a test command" do
|
||||
context "when executing the command fails" do
|
||||
context "when failures are fatal" do
|
||||
it "fails configuration with the correct error message" do
|
||||
test_dir "configure"
|
||||
create_exe "grep", "exit 4"
|
||||
result = run_rscons(rsconscript: "custom_config_check.rb", op: "configure")
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.stdout).to match /Checking 'grep' version\.\.\. error executing grep/
|
||||
expect(result.status).to_not eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context "when the custom logic indicates a failure" do
|
||||
it "fails configuration with the correct error message" do
|
||||
test_dir "configure"
|
||||
create_exe "grep", "echo 'grep (GNU grep) 1.1'"
|
||||
result = run_rscons(rsconscript: "custom_config_check.rb", op: "configure")
|
||||
expect(result.stderr).to match /Configuration failed/
|
||||
expect(result.stdout).to match /Checking 'grep' version\.\.\. too old!/
|
||||
expect(result.status).to_not eq 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when failures are not fatal" do
|
||||
context "when the custom logic indicates a failure" do
|
||||
it "displays the correct message and does not fail configuration" do
|
||||
test_dir "configure"
|
||||
create_exe "grep", "echo 'grep (GNU grep) 2.1'"
|
||||
result = run_rscons(rsconscript: "custom_config_check.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stdout).to match /Checking 'grep' version\.\.\. we'll work with it but you should upgrade/
|
||||
expect(result.status).to eq 0
|
||||
result = run_rscons(rsconscript: "custom_config_check.rb", op: "build")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stdout).to match /GREP_WORKAROUND/
|
||||
expect(result.status).to eq 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the custom logic indicates success" do
|
||||
it "passes configuration with the correct message" do
|
||||
test_dir "configure"
|
||||
create_exe "grep", "echo 'grep (GNU grep) 3.0'"
|
||||
result = run_rscons(rsconscript: "custom_config_check.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stdout).to match /Checking 'grep' version\.\.\. good!/
|
||||
expect(result.status).to eq 0
|
||||
result = run_rscons(rsconscript: "custom_config_check.rb", op: "build")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stdout).to match /GREP_FULL/
|
||||
expect(result.status).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
it "allows passing standard input data to the executed command" do
|
||||
test_dir "configure"
|
||||
result = run_rscons(rsconscript: "custom_config_check.rb", op: "configure")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stdout).to match /Checking sed -E flag\.\.\. good/
|
||||
expect(result.status).to eq 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "does everything" do
|
||||
test_dir "configure"
|
||||
create_exe "pkg-config", "echo '-DMYPACKAGE'"
|
||||
@@ -2034,8 +2236,8 @@ EOF
|
||||
expect(result.stdout).to match /Setting build directory\.\.\. bb/
|
||||
expect(result.stdout).to match %r{Setting prefix\.\.\. /my/prefix}
|
||||
expect(result.stdout).to match /Checking for C compiler\.\.\. gcc/
|
||||
expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. g++/
|
||||
expect(result.stdout).to match /Checking for D compiler\.\.\. gdc/
|
||||
expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. g\+\+/
|
||||
expect(result.stdout).to match /Checking for D compiler\.\.\. (gdc|ldc2)/
|
||||
expect(result.stdout).to match /Checking for package 'mypackage'\.\.\. found/
|
||||
expect(result.stdout).to match /Checking for C header 'stdio.h'\.\.\. found/
|
||||
expect(result.stdout).to match /Checking for C\+\+ header 'iostream'\.\.\. found/
|
||||
@@ -2062,11 +2264,13 @@ EOF
|
||||
expect(result.status).to_not eq 0
|
||||
end
|
||||
|
||||
it "exits with an error if configuration fails during autoconf" do
|
||||
it "exits with an error code and message if configuration fails during autoconf" do
|
||||
test_dir "configure"
|
||||
result = run_rscons(rsconscript: "autoconf_fail.rb")
|
||||
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"
|
||||
end
|
||||
|
||||
it "exits with an error if configuration has not been performed before attempting to create an environment" do
|
||||
@@ -2270,13 +2474,13 @@ EOF
|
||||
result = run_rscons(rsconscript: "install.rb", op: %W[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.o")).to be_truthy
|
||||
expect(File.exists?("build/e.1/src/one/one.c.o")).to be_truthy
|
||||
|
||||
result = run_rscons(rsconscript: "install.rb", op: %W[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.o")).to be_truthy
|
||||
expect(File.exists?("build/e.1/src/one/one.c.o")).to be_truthy
|
||||
expect(Dir.entries(prefix)).to match_array %w[. ..]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -121,7 +121,10 @@ EOF
|
||||
before(:each) do
|
||||
stub_const("File::PATH_SEPARATOR", ";")
|
||||
stub_const("RbConfig::CONFIG", "host_os" => "mingw")
|
||||
expect(ENV).to receive(:[]).with("PATH").and_return("C:\\bin;C:\\Windows")
|
||||
expect(ENV).to receive(:[]).with("PATH").and_return("C:\\none;C:\\bin;C:\\Windows")
|
||||
allow(File).to receive(:directory?).with("C:\\none").and_return(false)
|
||||
allow(File).to receive(:directory?).with("C:\\bin").and_return(true)
|
||||
allow(File).to receive(:directory?).with("C:\\Windows").and_return(true)
|
||||
allow(Dir).to receive(:entries).with("C:\\bin").and_return(%w[one.com])
|
||||
allow(Dir).to receive(:entries).with("C:\\Windows").and_return(%w[two.exe Three.bat])
|
||||
end
|
||||
@@ -197,12 +200,12 @@ EOF
|
||||
end
|
||||
end
|
||||
|
||||
describe ".parse_makefile_deps" do
|
||||
describe ".parse_dependency_file" do
|
||||
it 'handles dependencies on one line' do
|
||||
expect(File).to receive(:read).with('makefile').and_return(<<EOS)
|
||||
module.o: source.cc
|
||||
EOS
|
||||
expect(Util.parse_makefile_deps('makefile')).to eq ['source.cc']
|
||||
expect(Util.parse_dependency_file('makefile')).to eq ['source.cc']
|
||||
end
|
||||
|
||||
it 'handles dependencies split across many lines' do
|
||||
@@ -211,9 +214,22 @@ module.o: module.c \\
|
||||
module.h \\
|
||||
other.h
|
||||
EOS
|
||||
expect(Util.parse_makefile_deps('makefile')).to eq [
|
||||
expect(Util.parse_dependency_file('makefile')).to eq [
|
||||
'module.c', 'module.h', 'other.h']
|
||||
end
|
||||
|
||||
it "parses ldc2-style dependency lines" do
|
||||
expect(File).to receive(:read).with("deps.out").and_return(<<EOS)
|
||||
std.traits (/usr/lib/ldc/x86_64-linux-gnu/include/d/std/traits.d) : private : std.meta (/usr/lib/ldc/x86_64-linux-gnu/include/d/std/meta.d):staticIndexOf
|
||||
std.conv (/usr/lib/ldc/x86_64-linux-gnu/include/d/std/conv.d) : private : std.array (/usr/lib/ldc/x86_64-linux-gnu/include/d/std/array.d):array
|
||||
std.stdio (/usr/lib/ldc/x86_64-linux-gnu/include/d/std/stdio.d) : private static : core.sys.posix.sys.socket (/usr/lib/ldc/x86_64-linux-gnu/include/d/core/sys/posix/sys/socket.d) -> sock
|
||||
EOS
|
||||
expect(Util.parse_dependency_file("deps.out")).to eq [
|
||||
"/usr/lib/ldc/x86_64-linux-gnu/include/d/std/meta.d",
|
||||
"/usr/lib/ldc/x86_64-linux-gnu/include/d/std/array.d",
|
||||
"/usr/lib/ldc/x86_64-linux-gnu/include/d/core/sys/posix/sys/socket.d",
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
describe Rscons do
|
||||
|
||||
describe ".set_suffix" do
|
||||
it "changes the suffix to the new one" do
|
||||
expect(Rscons.set_suffix("foo.c", ".h")).to eq("foo.h")
|
||||
end
|
||||
|
||||
it "appends a suffix if the given file name does not have one" do
|
||||
expect(Rscons.set_suffix("bazz", ".d")).to eq("bazz.d")
|
||||
end
|
||||
end
|
||||
|
||||
describe ".get_system_shell" do
|
||||
before(:each) do
|
||||
Rscons.instance_variable_set(:@shell, nil)
|
||||
|
||||
Reference in new issue
Block a user