From 533ee9c16c773a016ce6dc51180d8232fdfa69da Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 18 Mar 2014 21:57:53 -0400 Subject: [PATCH] add CFile builder to create C/C++ sources from lex/yacc input files --- lib/rscons.rb | 2 ++ lib/rscons/builders/cfile.rb | 40 ++++++++++++++++++++++++++++++ spec/rscons/builders/cfile_spec.rb | 23 +++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 lib/rscons/builders/cfile.rb create mode 100644 spec/rscons/builders/cfile_spec.rb diff --git a/lib/rscons.rb b/lib/rscons.rb index 6b64b48..93e54dd 100644 --- a/lib/rscons.rb +++ b/lib/rscons.rb @@ -5,6 +5,7 @@ require_relative "rscons/varset" require_relative "rscons/version" # default builders +require_relative "rscons/builders/cfile" require_relative "rscons/builders/library" require_relative "rscons/builders/object" require_relative "rscons/builders/program" @@ -12,6 +13,7 @@ require_relative "rscons/builders/program" # Namespace module for rscons classes module Rscons DEFAULT_BUILDERS = [ + :CFile, :Library, :Object, :Program, diff --git a/lib/rscons/builders/cfile.rb b/lib/rscons/builders/cfile.rb new file mode 100644 index 0000000..558bd9e --- /dev/null +++ b/lib/rscons/builders/cfile.rb @@ -0,0 +1,40 @@ +module Rscons + module Builders + # Build a C or C++ source file given a lex (.l, .ll) or yacc (.y, .yy) + # input file. + # + # Examples:: + # env.CFile("parser.tab.cc", "parser.yy") + # env.CFile("lex.yy.cc", "parser.ll") + class CFile < Builder + def default_variables(env) + { + "YACC" => "bison", + "YACC_FLAGS" => ["-d"], + "YACC_CMD" => ["${YACC}", "${YACC_FLAGS}", "-o", "${_TARGET}", "${_SOURCES}"], + "LEX" => "flex", + "LEX_FLAGS" => [], + "LEX_CMD" => ["${LEX}", "${LEX_FLAGS}", "-o", "${_TARGET}", "${_SOURCES}"], + } + end + + def run(target, sources, cache, env, vars) + vars = vars.merge({ + "_TARGET" => target, + "_SOURCES" => sources, + }) + cmd = + case + when sources.first.end_with?(".l", ".ll") + "LEX" + when sources.first.end_with?(".y", ".yy") + "YACC" + else + raise "Unknown source file #{sources.first.inspect} for CFile builder" + end + command = env.build_command(env["#{cmd}_CMD"], vars) + standard_build("#{cmd} #{target}", target, command, sources, env, cache) + end + end + end +end diff --git a/spec/rscons/builders/cfile_spec.rb b/spec/rscons/builders/cfile_spec.rb new file mode 100644 index 0000000..829f8c9 --- /dev/null +++ b/spec/rscons/builders/cfile_spec.rb @@ -0,0 +1,23 @@ +module Rscons + module Builders + describe CFile do + let(:env) {Environment.new} + subject {CFile.new} + + it "invokes bison to create a .c file from a .y file" do + subject.should_receive(:standard_build).with("YACC parser.c", "parser.c", ["bison", "-d", "-o", "parser.c", "parser.y"], ["parser.y"], env, :cache) + subject.run("parser.c", ["parser.y"], :cache, env, {}) + end + + it "invokes a custom lexer to create a .cc file from a .ll file" do + env["LEX"] = "custom_lex" + subject.should_receive(:standard_build).with("LEX lexer.cc", "lexer.cc", ["custom_lex", "-o", "lexer.cc", "parser.ll"], ["parser.ll"], env, :cache) + subject.run("lexer.cc", ["parser.ll"], :cache, env, {}) + end + + it "raises an error when an unknown source file is specified" do + expect {subject.run("file.c", ["foo.bar"], :cache, env, {})}.to raise_error /Unknown source file .foo.bar. for CFile builder/ + end + end + end +end