Move rsconscache into build directory - close #136

This commit is contained in:
Josh Holtrop 2022-01-09 23:08:28 -05:00
parent a2f72c6b87
commit 97dbaeb82d
7 changed files with 56 additions and 28 deletions

View File

@ -78,9 +78,12 @@ cache file in order to avoid rebuilding a target when it is already up to date.
### Build Directory ### Build Directory
Rscons was designed to store temporary build artifacts (for example, object Rscons was designed to store temporary build artifacts (for example, object
files, dependency files, etc...) in a `build` directory. files, dependency files, etc...) and build system metadata in a
"build directory".
This keeps files generated by the build cleanly separated from user-controlled This keeps files generated by the build cleanly separated from user-controlled
source files. source files.
By default a build directory named "build" is used, but this can be overridden
by the user by using the `-b`/`--build` command-line option.
## Getting Started ## Getting Started
@ -94,7 +97,7 @@ To use Rscons on your project, you must:
Rscons is designed to be distributed as a stand-alone single file script that Rscons is designed to be distributed as a stand-alone single file script that
can be copied into and versioned in a project's source tree. can be copied into and versioned in a project's source tree.
The only dependency required to run Rscons is to have a Ruby interpreter The only requirement to run Rscons is that the system has a Ruby interpreter
installed. installed.
The latest release can be downloaded from [https://github.com/holtrop/rscons/releases](https://github.com/holtrop/rscons/releases). 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 Simply copy the `rscons` executable script into the desired location within

View File

@ -5,6 +5,10 @@ module Rscons
# Functionality for an instance of the rscons application invocation. # Functionality for an instance of the rscons application invocation.
class Application class Application
# @return [String]
# Top-level build directory.
attr_accessor :build_dir
# @return [Boolean] # @return [Boolean]
# Whether to output ANSI color escape sequences. # Whether to output ANSI color escape sequences.
attr_accessor :do_ansi_color attr_accessor :do_ansi_color
@ -23,6 +27,7 @@ module Rscons
# Create Application instance. # Create Application instance.
def initialize def initialize
@build_dir = "build"
@n_threads = Util.determine_n_threads @n_threads = Util.determine_n_threads
@vars = VarSet.new @vars = VarSet.new
@operations = Set.new @operations = Set.new
@ -171,11 +176,8 @@ module Rscons
# Exit code. # Exit code.
def distclean def distclean
cache = Cache.instance cache = Cache.instance
build_dir = cache["configuration_data"]["build_dir"]
clean clean
if build_dir FileUtils.rm_rf(@build_dir)
FileUtils.rm_rf(build_dir)
end
cache.clear cache.clear
0 0
end end

View File

@ -51,9 +51,6 @@ module Rscons
# } # }
class Cache class Cache
# Name of the file to store cache information in
CACHE_FILE = ".rsconscache"
# Prefix for phony cache entries. # Prefix for phony cache entries.
PHONY_PREFIX = ":PHONY:" PHONY_PREFIX = ":PHONY:"
@ -70,6 +67,11 @@ module Rscons
initialize! initialize!
end end
# Get the path to the cache file.
def cache_file
File.join(Rscons.application.build_dir, ".rsconscache")
end
# Access cache value. # Access cache value.
def [](key) def [](key)
@cache[key] @cache[key]
@ -84,7 +86,7 @@ module Rscons
# #
# @return [void] # @return [void]
def clear def clear
FileUtils.rm_f(CACHE_FILE) FileUtils.rm_f(cache_file)
initialize! initialize!
end end
@ -100,7 +102,7 @@ module Rscons
# @return [void] # @return [void]
def write def write
@cache["version"] = VERSION @cache["version"] = VERSION
File.open(CACHE_FILE, "w") do |fh| File.open(cache_file, "w") do |fh|
fh.puts(JSON.dump(@cache)) fh.puts(JSON.dump(@cache))
end end
end end
@ -360,9 +362,9 @@ module Rscons
# Create a Cache object and load in the previous contents from the cache # Create a Cache object and load in the previous contents from the cache
# file. # file.
def initialize! def initialize!
@cache = JSON.load(File.read(CACHE_FILE)) rescue {} @cache = JSON.load(File.read(cache_file)) rescue {}
unless @cache.is_a?(Hash) unless @cache.is_a?(Hash)
$stderr.puts "Warning: #{CACHE_FILE} was corrupt. Contents:\n#{@cache.inspect}" $stderr.puts "Warning: #{cache_file} was corrupt. Contents:\n#{@cache.inspect}"
@cache = {} @cache = {}
end end
@cache["targets"] ||= {} @cache["targets"] ||= {}

View File

@ -6,6 +6,7 @@ USAGE = <<EOF
Usage: #{$0} [global options] [operation] [operation options] Usage: #{$0} [global options] [operation] [operation options]
Global options: Global options:
-b BUILD, --build=BUILD Set build directory (default: build)
-f FILE Use FILE as Rsconscript -f FILE Use FILE as Rsconscript
-F, --show-failure Show failed command log from previous build and exit -F, --show-failure Show failed command log from previous build and exit
-h, --help Show rscons help and exit -h, --help Show rscons help and exit
@ -23,7 +24,6 @@ Operations:
uninstall Uninstall project from installation destination uninstall Uninstall project from installation destination
Configure options: Configure options:
-b BUILD, --build=BUILD Set build directory (default: build)
--prefix=PREFIX Set installation prefix (default: /usr/local) --prefix=PREFIX Set installation prefix (default: /usr/local)
EOF EOF
@ -56,6 +56,10 @@ module Rscons
private private
def add_global_options(opts) def add_global_options(opts)
opts.on("-b", "--build DIR") do |build_dir|
Rscons.application.build_dir = build_dir
end
opts.on("-j NTHREADS") do |n_threads| opts.on("-j NTHREADS") do |n_threads|
Rscons.application.n_threads = n_threads.to_i Rscons.application.n_threads = n_threads.to_i
end end
@ -156,10 +160,6 @@ module Rscons
end end
def parse_configure_args(opts, argv, options) def parse_configure_args(opts, argv, options)
opts.on("-b", "--build DIR") do |build_dir|
options[:build_dir] = build_dir
end
opts.on("--prefix PREFIX") do |prefix| opts.on("--prefix PREFIX") do |prefix|
options[:prefix] = prefix options[:prefix] = prefix
end end

View File

@ -9,30 +9,25 @@ module Rscons
# #
# @param options [Hash] # @param options [Hash]
# Optional parameters. # Optional parameters.
# @option options [String] :build_dir
# Build directory.
# @option options [String] :prefix # @option options [String] :prefix
# Install prefix. # Install prefix.
# @option options [String] :project_name # @option options [String] :project_name
# Project name. # Project name.
def initialize(options) def initialize(options)
# Default options. # Default options.
options[:build_dir] ||= "build"
options[:prefix] ||= "/usr/local" options[:prefix] ||= "/usr/local"
@work_dir = "#{options[:build_dir]}/configure" @work_dir = "#{Rscons.application.build_dir}/configure"
FileUtils.mkdir_p(@work_dir) FileUtils.mkdir_p(@work_dir)
@log_fh = File.open("#{@work_dir}/config.log", "wb") @log_fh = File.open("#{@work_dir}/config.log", "wb")
cache = Cache.instance cache = Cache.instance
cache["failed_commands"] = [] cache["failed_commands"] = []
cache["configuration_data"] = {} cache["configuration_data"] = {}
cache["configuration_data"]["build_dir"] = options[:build_dir]
cache["configuration_data"]["prefix"] = options[:prefix] cache["configuration_data"]["prefix"] = options[:prefix]
if project_name = options[:project_name] if project_name = options[:project_name]
Ansi.write($stdout, "Configuring ", :cyan, project_name, :reset, "...\n") Ansi.write($stdout, "Configuring ", :cyan, project_name, :reset, "...\n")
else else
$stdout.puts "Configuring project..." $stdout.puts "Configuring project..."
end end
Ansi.write($stdout, "Setting build directory... ", :green, options[:build_dir], :reset, "\n")
Ansi.write($stdout, "Setting prefix... ", :green, options[:prefix], :reset, "\n") Ansi.write($stdout, "Setting prefix... ", :green, options[:prefix], :reset, "\n")
store_merge("prefix" => options[:prefix]) store_merge("prefix" => options[:prefix])
end end

View File

@ -97,7 +97,7 @@ module Rscons
else else
:short :short
end end
@build_root = "#{Cache.instance["configuration_data"]["build_dir"]}/e.#{@id}" @build_root = "#{Rscons.application.build_dir}/e.#{@id}"
@n_threads = Rscons.application.n_threads @n_threads = Rscons.application.n_threads
if block_given? if block_given?

View File

@ -208,6 +208,15 @@ EOF
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n" expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
end end
it "builds a C program with one source file in an alternate build directory" do
test_dir("simple")
result = run_rscons(rscons_args: %w[-b b])
expect(result.stderr).to eq ""
expect(Dir.exist?("build")).to be_falsey
expect(File.exists?("b/e.1/simple.c.o")).to be_truthy
expect(nr(`./simple.exe`)).to eq "This is a simple C program\n"
end
it "allows specifying a Builder object as the source to another build target" do it "allows specifying a Builder object as the source to another build target" do
test_dir("simple") test_dir("simple")
result = run_rscons(rsconscript: "builder_as_source.rb") result = run_rscons(rsconscript: "builder_as_source.rb")
@ -1296,7 +1305,8 @@ EOF
context "Cache management" do context "Cache management" do
it "prints a warning when the cache is corrupt" do it "prints a warning when the cache is corrupt" do
test_dir("simple") test_dir("simple")
File.open(Rscons::Cache::CACHE_FILE, "w") do |fh| FileUtils.mkdir("build")
File.open("build/.rsconscache", "w") do |fh|
fh.puts("[1]") fh.puts("[1]")
end end
result = run_rscons result = run_rscons
@ -1748,6 +1758,22 @@ EOF
expect(result.status).to_not eq 0 expect(result.status).to_not eq 0
end end
it "automatically runs the configure operation if the project is not yet configured in the given build directory" do
test_dir "configure"
result = run_rscons(rsconscript: "check_c_compiler.rb")
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to match /Checking for C compiler\.\.\./
expect(Dir.exist?("build/configure")).to be_truthy
result = run_rscons(rsconscript: "check_c_compiler.rb", rscons_args: %w[--build=bb])
expect(result.stderr).to eq ""
expect(result.status).to eq 0
expect(result.stdout).to match /Checking for C compiler\.\.\./
expect(Dir.exist?("bb/configure")).to be_truthy
end
context "check_c_compiler" do context "check_c_compiler" do
{"check_c_compiler.rb" => "when no arguments are given", {"check_c_compiler.rb" => "when no arguments are given",
"check_c_compiler_find_first.rb" => "when arguments are given"}.each_pair do |rsconscript, desc| "check_c_compiler_find_first.rb" => "when arguments are given"}.each_pair do |rsconscript, desc|
@ -2284,7 +2310,6 @@ EOF
expect(result.stderr).to eq "" expect(result.stderr).to eq ""
expect(result.status).to eq 0 expect(result.status).to eq 0
expect(result.stdout).to match /Configuring configure test\.\.\./ expect(result.stdout).to match /Configuring configure test\.\.\./
expect(result.stdout).to match /Setting build directory\.\.\. bb/
expect(result.stdout).to match %r{Setting prefix\.\.\. /my/prefix} 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\.\.\. gcc/
expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. g\+\+/ expect(result.stdout).to match /Checking for C\+\+ compiler\.\.\. g\+\+/
@ -2295,6 +2320,8 @@ EOF
expect(result.stdout).to match /Checking for D import 'std.stdio'\.\.\. found/ expect(result.stdout).to match /Checking for D import 'std.stdio'\.\.\. found/
expect(result.stdout).to match /Checking for library 'm'\.\.\. found/ expect(result.stdout).to match /Checking for library 'm'\.\.\. found/
expect(result.stdout).to match /Checking for program 'ls'\.\.\. .*ls/ expect(result.stdout).to match /Checking for program 'ls'\.\.\. .*ls/
expect(Dir.exist?("build")).to be_falsey
expect(Dir.exist?("bb/configure")).to be_truthy
end end
it "aggregates multiple set_define's" do it "aggregates multiple set_define's" do
@ -2357,7 +2384,6 @@ EOF
expect(result.status).to eq 0 expect(result.status).to eq 0
expect(File.exists?("simple.o")).to be_falsey expect(File.exists?("simple.o")).to be_falsey
expect(File.exists?("build")).to be_falsey expect(File.exists?("build")).to be_falsey
expect(File.exists?(Rscons::Cache::CACHE_FILE)).to be_falsey
end end
end end