From ea2b1e73d1a29d1fd0971c0ecbd889f2c899e01a Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 14 Apr 2019 12:35:28 -0400 Subject: [PATCH] add direct mode to Program builder - close #61 --- build_tests/direct/c_program.rb | 5 +++ build_tests/direct/c_shared_library.rb | 7 +++ build_tests/direct/main.c | 7 +++ build_tests/direct/three.c | 7 +++ build_tests/direct/three.h | 1 + build_tests/direct/two.c | 7 +++ build_tests/direct/two.h | 1 + lib/rscons/builders/lang/asm.rb | 4 +- lib/rscons/builders/lang/c.rb | 4 +- lib/rscons/builders/lang/cxx.rb | 4 +- lib/rscons/builders/lang/d.rb | 4 +- lib/rscons/builders/mixins/object.rb | 22 ++++++++-- lib/rscons/builders/program.rb | 16 +++++-- lib/rscons/builders/shared_library.rb | 24 ++++++++--- lib/rscons/default_construction_variables.rb | 7 +++ lib/rscons/environment.rb | 4 +- spec/build_tests_spec.rb | 45 ++++++++++++++++++++ 17 files changed, 146 insertions(+), 23 deletions(-) create mode 100644 build_tests/direct/c_program.rb create mode 100644 build_tests/direct/c_shared_library.rb create mode 100644 build_tests/direct/main.c create mode 100644 build_tests/direct/three.c create mode 100644 build_tests/direct/three.h create mode 100644 build_tests/direct/two.c create mode 100644 build_tests/direct/two.h diff --git a/build_tests/direct/c_program.rb b/build_tests/direct/c_program.rb new file mode 100644 index 0000000..0269e84 --- /dev/null +++ b/build_tests/direct/c_program.rb @@ -0,0 +1,5 @@ +build do + Environment.new do |env| + env.Program("test.exe", Rscons.glob("*.c"), direct: true) + end +end diff --git a/build_tests/direct/c_shared_library.rb b/build_tests/direct/c_shared_library.rb new file mode 100644 index 0000000..12d5c94 --- /dev/null +++ b/build_tests/direct/c_shared_library.rb @@ -0,0 +1,7 @@ +build do + Environment.new do |env| + lib = env.SharedLibrary("mylib", ["two.c", "three.c"], direct: true) + program = env.Program("test.exe", "main.c", "LIBS" => ["mylib"], "LIBPATH" => ["."]) + env.depends(program, lib) + end +end diff --git a/build_tests/direct/main.c b/build_tests/direct/main.c new file mode 100644 index 0000000..864ef1d --- /dev/null +++ b/build_tests/direct/main.c @@ -0,0 +1,7 @@ +#include "two.h" + +int main(int argc, char * argv[]) +{ + two(); + return 0; +} diff --git a/build_tests/direct/three.c b/build_tests/direct/three.c new file mode 100644 index 0000000..a1f50b3 --- /dev/null +++ b/build_tests/direct/three.c @@ -0,0 +1,7 @@ +#include "three.h" +#include + +void three(void) +{ + printf("three\n"); +} diff --git a/build_tests/direct/three.h b/build_tests/direct/three.h new file mode 100644 index 0000000..aca98c6 --- /dev/null +++ b/build_tests/direct/three.h @@ -0,0 +1 @@ +void three(void); diff --git a/build_tests/direct/two.c b/build_tests/direct/two.c new file mode 100644 index 0000000..61f8ba9 --- /dev/null +++ b/build_tests/direct/two.c @@ -0,0 +1,7 @@ +#include "two.h" +#include "three.h" + +void two(void) +{ + three(); +} diff --git a/build_tests/direct/two.h b/build_tests/direct/two.h new file mode 100644 index 0000000..f3ab72d --- /dev/null +++ b/build_tests/direct/two.h @@ -0,0 +1 @@ +void two(void); diff --git a/lib/rscons/builders/lang/asm.rb b/lib/rscons/builders/lang/asm.rb index 98fc071..865776d 100644 --- a/lib/rscons/builders/lang/asm.rb +++ b/lib/rscons/builders/lang/asm.rb @@ -1,2 +1,2 @@ -Rscons::Builders::Object.register(command: "${ASCMD}", suffix: "${ASSUFFIX}", short_description: "Assembling") -Rscons::Builders::SharedObject.register(command: "${ASCMD}", suffix: "${ASSUFFIX}", short_description: "Assembling") +Rscons::Builders::Object.register(command: "${ASCMD}", direct_command: "${ASCMD:direct}", suffix: "${ASSUFFIX}", short_description: "Assembling") +Rscons::Builders::SharedObject.register(command: "${ASCMD}", direct_command: "${ASCMD:direct}", suffix: "${ASSUFFIX}", short_description: "Assembling") diff --git a/lib/rscons/builders/lang/c.rb b/lib/rscons/builders/lang/c.rb index de74149..66c579e 100644 --- a/lib/rscons/builders/lang/c.rb +++ b/lib/rscons/builders/lang/c.rb @@ -1,2 +1,2 @@ -Rscons::Builders::Object.register(command: "${CCCMD}", suffix: "${CSUFFIX}") -Rscons::Builders::SharedObject.register(command: "${SHCCCMD}", suffix: "${CSUFFIX}") +Rscons::Builders::Object.register(command: "${CCCMD}", direct_command: "${CCCMD:direct}", suffix: "${CSUFFIX}") +Rscons::Builders::SharedObject.register(command: "${SHCCCMD}", direct_command: "${SHCCCMD:direct}", suffix: "${CSUFFIX}") diff --git a/lib/rscons/builders/lang/cxx.rb b/lib/rscons/builders/lang/cxx.rb index aec5cd7..b8dd5ac 100644 --- a/lib/rscons/builders/lang/cxx.rb +++ b/lib/rscons/builders/lang/cxx.rb @@ -1,2 +1,2 @@ -Rscons::Builders::Object.register(command: "${CXXCMD}", suffix: "${CXXSUFFIX}", preferred_ld: "${CXX}") -Rscons::Builders::SharedObject.register(command: "${SHCXXCMD}", suffix: "${CXXSUFFIX}", preferred_ld: "${SHCXX}") +Rscons::Builders::Object.register(command: "${CXXCMD}", direct_command: "${CXXCMD:direct}", suffix: "${CXXSUFFIX}", preferred_ld: "${CXX}") +Rscons::Builders::SharedObject.register(command: "${SHCXXCMD}", direct_command: "${SHCXXCMD:direct}", suffix: "${CXXSUFFIX}", preferred_ld: "${SHCXX}") diff --git a/lib/rscons/builders/lang/d.rb b/lib/rscons/builders/lang/d.rb index a74c400..1ae36d2 100644 --- a/lib/rscons/builders/lang/d.rb +++ b/lib/rscons/builders/lang/d.rb @@ -1,2 +1,2 @@ -Rscons::Builders::Object.register(command: "${DCCMD}", suffix: "${DSUFFIX}", preferred_ld: "${DC}") -Rscons::Builders::SharedObject.register(command: "${SHDCCMD}", suffix: "${DSUFFIX}", preferred_ld: "${SHDC}") +Rscons::Builders::Object.register(command: "${DCCMD}", direct_command: "${DCCMD:direct}", suffix: "${DSUFFIX}", preferred_ld: "${DC}") +Rscons::Builders::SharedObject.register(command: "${SHDCCMD}", direct_command: "${SHDCCMD:direct}", suffix: "${DSUFFIX}", preferred_ld: "${SHDC}") diff --git a/lib/rscons/builders/mixins/object.rb b/lib/rscons/builders/mixins/object.rb index f425187..f1cd899 100644 --- a/lib/rscons/builders/mixins/object.rb +++ b/lib/rscons/builders/mixins/object.rb @@ -55,7 +55,12 @@ module Rscons unless build_params raise "Unknown input file type: #{@sources.first.inspect}" end - @command_template = build_params[:command] + @command_template = + if @vars[:direct] + build_params[:direct_command] + else + build_params[:command] + end @short_description = build_params[:short_description] || "Compiling" @preferred_ld = build_params[:preferred_ld] end @@ -67,10 +72,21 @@ module Rscons else @vars["_TARGET"] = @target @vars["_SOURCES"] = @sources - @vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars)) + depfilesuffix = @env.expand_varref("${DEPFILESUFFIX}", vars) + @vars["_DEPFILE"] = + if @vars[:direct] + @env.get_build_fname(target, depfilesuffix, self.class) + else + Rscons.set_suffix(target, depfilesuffix) + end + @cache.mkdir_p(File.dirname(@vars["_DEPFILE"])) command = @env.build_command(@command_template, @vars) @env.produces(@target, @vars["_DEPFILE"]) - message = "#{@short_description} #{Util.short_format_paths(@sources)}" + if @vars[:direct] + message = "#{@short_description}/Linking #{Util.short_format_paths(@sources)} => #{@target}" + else + message = "#{@short_description} #{Util.short_format_paths(@sources)}" + end standard_command(message, command) end end diff --git a/lib/rscons/builders/program.rb b/lib/rscons/builders/program.rb index cba1ffc..2097d10 100644 --- a/lib/rscons/builders/program.rb +++ b/lib/rscons/builders/program.rb @@ -7,12 +7,22 @@ module Rscons include Mixins::ObjectDeps include Mixins::Program + class << self + def new(options, *more) + unless File.basename(options[:target])["."] + options[:target] += options[:env].expand_varref("${PROGSUFFIX}", options[:vars]) + end + if options[:vars][:direct] + Object.new(options, *more) + else + super + end + end + end + # Create an instance of the Builder to build a target. def initialize(options) super(options) - unless File.basename(@target)["."] - @target += @env.expand_varref("${PROGSUFFIX}", @vars) - end @objects = register_object_deps(Object) end diff --git a/lib/rscons/builders/shared_library.rb b/lib/rscons/builders/shared_library.rb index 0106eeb..37a2a75 100644 --- a/lib/rscons/builders/shared_library.rb +++ b/lib/rscons/builders/shared_library.rb @@ -7,16 +7,26 @@ module Rscons include Mixins::ObjectDeps include Mixins::Program + class << self + def new(options, *more) + libprefix = options[:env].expand_varref("${SHLIBPREFIX}", options[:vars]) + unless File.basename(options[:target]).start_with?(libprefix) + options[:target] = options[:target].sub!(%r{^(.*/)?([^/]+)$}, "\\1#{libprefix}\\2") + end + unless File.basename(options[:target])["."] + options[:target] += options[:env].expand_varref("${SHLIBSUFFIX}", options[:vars]) + end + if options[:vars][:direct] + SharedObject.new(options, *more) + else + super + end + end + end + # Create an instance of the Builder to build a target. def initialize(options) super(options) - libprefix = @env.expand_varref("${SHLIBPREFIX}", @vars) - unless File.basename(@target).start_with?(libprefix) - @target = @target.sub!(%r{^(.*/)?([^/]+)$}, "\\1#{libprefix}\\2") - end - unless File.basename(@target)["."] - @target += @env.expand_varref("${SHLIBSUFFIX}", @vars) - end @objects = register_object_deps(SharedObject) end diff --git a/lib/rscons/default_construction_variables.rb b/lib/rscons/default_construction_variables.rb index 5f45fbf..c065383 100644 --- a/lib/rscons/default_construction_variables.rb +++ b/lib/rscons/default_construction_variables.rb @@ -10,6 +10,7 @@ module Rscons "ARFLAGS" => %w[rcs], "AS" => "${CC}", "ASCMD" => %w[${AS} -c -o ${_TARGET} ${ASDEPGEN} ${INCPREFIX}${ASPPPATH} ${ASPPFLAGS} ${ASFLAGS} ${_SOURCES}], + "ASCMD:direct" => %w[${AS} -o ${_TARGET} ${ASDEPGEN} ${INCPREFIX}${ASPPPATH} ${ASPPFLAGS} ${ASFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}], "ASDEPGEN" => %w[-MMD -MF ${_DEPFILE}], "ASFLAGS" => [], "ASPPFLAGS" => "${CPPFLAGS}", @@ -17,6 +18,7 @@ module Rscons "ASSUFFIX" => %w[.S], "CC" => "gcc", "CCCMD" => %w[${CC} -c -o ${_TARGET} ${CCDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${CFLAGS} ${CCFLAGS} ${_SOURCES}], + "CCCMD:direct" => %w[${CC} -o ${_TARGET} ${CCDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${CFLAGS} ${CCFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}], "CCDEPGEN" => %w[-MMD -MF ${_DEPFILE}], "CCFLAGS" => [], "CFLAGS" => [], @@ -28,11 +30,13 @@ module Rscons "CSUFFIX" => %w[.c], "CXX" => "g++", "CXXCMD" => %w[${CXX} -c -o ${_TARGET} ${CXXDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${CXXFLAGS} ${CCFLAGS} ${_SOURCES}], + "CXXCMD:direct" => %w[${CXX} -o ${_TARGET} ${CXXDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${CXXFLAGS} ${CCFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}], "CXXDEPGEN" => %w[-MMD -MF ${_DEPFILE}], "CXXFLAGS" => [], "CXXSUFFIX" => %w[.cc .cpp .cxx .C], "DC" => "gdc", "DCCMD" => %w[${DC} -c -o ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${_SOURCES}], + "DCCMD:direct" => %w[${DC} -o ${_TARGET} ${DDEPGEN} ${INCPREFIX}${D_IMPORT_PATH} ${DFLAGS} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}], "DDEPGEN" => %w[-MMD -MF ${_DEPFILE}], "DEPFILESUFFIX" => ".mf", "DFLAGS" => [], @@ -58,13 +62,16 @@ module Rscons "PROGSUFFIX" => on_windows ? ".exe" : "", "SHCC" => "${CC}", "SHCCCMD" => %w[${SHCC} -c -o ${_TARGET} ${CCDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${SHCFLAGS} ${SHCCFLAGS} ${_SOURCES}], + "SHCCCMD:direct" => %w[${SHCC} -o ${_TARGET} ${CCDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${SHCFLAGS} ${SHCCFLAGS} ${SHLDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}], "SHCCFLAGS" => %w[${CCFLAGS}] + pic_flags, "SHCFLAGS" => %w[${CFLAGS}], "SHCXX" => "${CXX}", "SHCXXCMD" => %w[${SHCXX} -c -o ${_TARGET} ${CXXDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${SHCXXFLAGS} ${SHCCFLAGS} ${_SOURCES}], + "SHCXXCMD:direct" => %w[${SHCXX} -o ${_TARGET} ${CXXDEPGEN} ${INCPREFIX}${CPPPATH} ${CPPFLAGS} ${SHCXXFLAGS} ${SHCCFLAGS} ${SHLDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}], "SHCXXFLAGS" => %w[${CXXFLAGS}], "SHDC" => "gdc", "SHDCCMD" => %w[${SHDC} -c -o ${_TARGET} ${INCPREFIX}${D_IMPORT_PATH} ${SHDFLAGS} ${_SOURCES}], + "SHDCCMD:direct" => %w[${SHDC} -o ${_TARGET} ${INCPREFIX}${D_IMPORT_PATH} ${SHDFLAGS} ${SHLDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}], "SHDFLAGS" => %w[${DFLAGS}] + pic_flags, "SHLD" => nil, "SHLDCMD" => %w[${SHLD} -o ${_TARGET} ${SHLDFLAGS} ${_SOURCES} ${SHLIBDIRPREFIX}${LIBPATH} ${SHLIBLINKPREFIX}${LIBS}], diff --git a/lib/rscons/environment.rb b/lib/rscons/environment.rb index acf2a73..6d581f6 100644 --- a/lib/rscons/environment.rb +++ b/lib/rscons/environment.rb @@ -314,7 +314,7 @@ module Rscons end target = expand_path(expand_varref(target)) sources = Array(sources).map do |source| - source = source.target if sources.is_a?(Builder) + source = source.target if source.is_a?(Builder) expand_path(expand_varref(source)) end.flatten builder = @builders[method.to_s].new( @@ -507,7 +507,7 @@ module Rscons # @param short_description [String] # Builder short description, printed if the echo mode is :short, or if # there is no command. - # @param command [Array] + # @param command [Array, nil] # Builder command, printed if the echo mode is :command. # # @return [void] diff --git a/spec/build_tests_spec.rb b/spec/build_tests_spec.rb index b3617dc..fb00e74 100644 --- a/spec/build_tests_spec.rb +++ b/spec/build_tests_spec.rb @@ -2079,4 +2079,49 @@ EOF end end + context "direct mode" do + it "allows calling Program builder in direct mode and passes all sources to the C compiler" do + test_dir("direct") + + result = run_rscons(rsconscript: "c_program.rb") + expect(result.stderr).to eq "" + expect(result.stdout).to match %r{Compiling/Linking} + expect(File.exists?("test.exe")).to be_truthy + expect(`./test.exe`).to match /three/ + + result = run_rscons(rsconscript: "c_program.rb") + expect(result.stdout).to eq "" + + three_h = File.read("three.h", mode: "rb") + File.open("three.h", "wb") do |fh| + fh.write(three_h) + fh.puts("#define FOO 42") + end + result = run_rscons(rsconscript: "c_program.rb") + expect(result.stdout).to match %r{Compiling/Linking} + end + + it "allows calling SharedLibrary builder in direct mode and passes all sources to the C compiler" do + test_dir("direct") + + result = run_rscons(rsconscript: "c_shared_library.rb") + expect(result.stderr).to eq "" + expect(result.stdout).to match %r{Compiling/Linking} + expect(File.exists?("test.exe")).to be_truthy + ld_library_path_prefix = (RUBY_PLATFORM =~ /mingw/ ? "" : "LD_LIBRARY_PATH=. ") + expect(`#{ld_library_path_prefix}./test.exe`).to match /three/ + + result = run_rscons(rsconscript: "c_shared_library.rb") + expect(result.stdout).to eq "" + + three_h = File.read("three.h", mode: "rb") + File.open("three.h", "wb") do |fh| + fh.write(three_h) + fh.puts("#define FOO 42") + end + result = run_rscons(rsconscript: "c_shared_library.rb") + expect(result.stdout).to match %r{Compiling/Linking} + end + end + end