#!/usr/bin/ruby # # BuildProject board=... mcu=... -- FILE1 FILE2 FILE3 # # AVRsack # # Created by Matthias Neeracher on 11/26/14. # Copyright © 2014 Aere Perennius. All rights reserved. # require 'fileutils.rb' require 'rake' BUILD = { 'board' => 'uno', 'mcu' => 'atmega328p', 'f_cpu' => 16000000, 'core' => 'arduino', 'variant' => 'standard', } def parseArguments while ARGV.length > 0 do param = ARGV.shift break if param == '--' param =~ /(\S+?)=(\S*)/ BUILD[$1] = $2 end end def createBuildDirectory $BUILD_DIR = "build/#{BUILD['board']}" $SKETCH_DIR = "#{$BUILD_DIR}/sketch" FileUtils::mkdir_p "#{$SKETCH_DIR}", :verbose => true end HEADERMAP = {} def buildHeaderMap paths = Rake::FileList.new(BUILD['libs'].split(':').reverse) paths.each do |path| libs = Rake::FileList.new(path+"/*") libs.each do |lib| headers = Rake::FileList.new(lib+"/**/*.h") headers.each do |h| name = h[lib.length+1..-1] next if name =~ %r|^utility/| if !HEADERMAP[name] or HEADERMAP[name].pathmap('%f') != name.pathmap('%X') HEADERMAP[name] = lib end end end end end LIBRARIES = Rake::FileList[] CORES = Rake::FileList[] def parseInoFiles CORES.add(BUILD['core_path']) if BUILD['variant_path'] CORES.add(BUILD['variant_path']) end ARGV.each_index do |arg| if ARGV[arg] =~ /\.ino$/ outName = "#{$SKETCH_DIR}/"+File.basename(ARGV[arg], '.ino')+".cpp" outFile = File.open(outName, 'w') File.open(ARGV[arg], 'r') do |ino| contents = ino.read # Find protypes: prototypes = contents.dup # - Strip comments, quoted strings, and preprocessor directives prototypes.gsub!(%r{'(?:[^']|\\')+'|"(?:[^"]|\\")*"|//.*?$|/\*.*?\*/|^\s*?#.*?$}m, ' ') # Collapse braces while prototypes.sub!(/(\{)(?:[^{}]+|\{[^{}]*\})/m, '\1') do end existingProto = {} prototypes.scan(/[\w\[\]\*]+\s+[&\[\]\*\w\s]+\([&,\[\]\*\w\s]*\)(?=\s*;)/) {|p| existingProto[smashSpaces(p)] = true } proto = [] prototypes.scan(/[\w\[\]\*]+\s+[&\[\]\*\w\s]+\([&,\[\]\*\w\s]*\)(?=\s*{)/) {|p| p = smashSpaces(p) proto << p+";\n" unless existingProto[p] } contents.each_line do |line| if line =~ /^\s*#include\s+[<"](.*)[">]\s*(#.*)?$/ addLibrary($1) end end %r{(?(?:\s+|//.*$|/\*.*?\*/)*)(?.*)}m =~ contents outFile.print preamble outFile.puts '#include "Arduino.h"' outFile.print proto.join('') outFile.puts "#line #{1+preamble.count("\n")}" outFile.print rest end outFile.close FileUtils.touch outName, :mtime => File.mtime(ARGV[arg]) ARGV[arg] = outName end end end def smashSpaces(s) return s.gsub(/(\W)\s+(\W)/, '\1\2').gsub(/\s+/, ' ') end def addLibrary(header) lib = HEADERMAP[header] if lib && !LIBRARIES.include?(lib) LIBRARIES.add(lib) end end parseArguments createBuildDirectory buildHeaderMap parseInoFiles File.open("#{$BUILD_DIR}/Rakefile", 'w') do |rakeFile| SOURCES = Rake::FileList.new(ARGV).select {|f| f =~ /\.(c|cpp|cp|cxx|S)$/} INCLUDES= (CORES+LIBRARIES).map {|l| " +\n \" -I'#{l}'\""}.join('') rakeFile.print < [sources[i],dest] do sh "%s %s '%s' -o '%s'" % [CC, extrainc ? "-I '"+extrainc+"'" : '', sources[i], objects[i]] end end file archive => objects do sh ("%s '%s' " % [AR, archive])+objects.map {|o| "'"+o+"'"}.join(" ") end end def compile_library(lib) extrainc = nil utility = lib+"/utility" if File::exists?(utility) extrainc = utility end compile(lib.pathmap('lib/%f'), extrainc, *Rake::FileList[lib+"/*.{c,cpp,cp,cxx,S}", lib+"/utility/*.{c,cpp,cp,cxx,S}"]) end def compile_core(core,variant) list = Rake::FileList[core+"/*.{c,cpp,cp,cxx,S}"] list.add(variant+"/*.{c,cpp,cp,cxx,S}") if variant compile('core', nil, list) end compile('sketch', nil, #{SOURCES.map{|f| "'../../"+f+"'"}.join(', ')}) compile_core(#{CORES.map {|c| "'"+c+"'"}.join(", ")}) #{LIBRARIES.pathmap("compile_library('%p')\n").join('')} file '#{BUILD['project']}.elf' => %w[sketch.a #{LIBRARIES.pathmap("lib/%f.a").join(" ")} core.a] do |task| sh ("%s -o %s -Wl,'-(' " % [LD, task.name])+task.prerequisites.map {|a| "'"+a+"'"}.join(" ")+" -Wl,'-)' -lm" end file '#{BUILD['project']}.eep' => '#{BUILD['project']}.elf' do |task| sh "%s '%s' '%s'" % [EEP, task.prerequisites[0], task.name] end file '#{BUILD['project']}.hex' => '#{BUILD['project']}.elf' do |task| sh "%s '%s' '%s'" % [HEX, task.prerequisites[0], task.name] end task :default => ['#{BUILD['project']}.eep', '#{BUILD['project']}.hex'] END_RAKE end