AVRSack/AVRsack/BuildProject

200 lines
7.0 KiB
Plaintext
Raw Permalink Normal View History

2014-11-28 13:18:53 +00:00
#!/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'
2014-11-30 21:32:14 +00:00
require 'rake'
2014-11-28 13:18:53 +00:00
BUILD = {
'board' => 'uno',
'mcu' => 'atmega328p',
'f_cpu' => 16000000,
'core' => 'arduino',
'variant' => 'standard',
2014-12-01 03:12:23 +00:00
'max_size'=> 32256
2014-11-28 13:18:53 +00:00
}
def parseArguments
while ARGV.length > 0 do
param = ARGV.shift
break if param == '--'
param =~ /(\S+?)=(\S*)/
BUILD[$1] = $2
end
end
def createBuildDirectory
2014-12-01 00:44:05 +00:00
buildDir = "build/#{BUILD['board']}"
sketchDir = "#{buildDir}/sketch"
FileUtils::mkdir_p "#{sketchDir}", :verbose => true
Dir.chdir(buildDir)
2014-11-28 13:18:53 +00:00
end
2014-11-30 21:32:14 +00:00
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
2014-12-01 00:20:48 +00:00
LIBRARIES = Rake::FileList[]
CORES = Rake::FileList[]
SKETCHES = Rake::FileList[]
2014-12-01 00:20:48 +00:00
2014-11-28 13:18:53 +00:00
def parseInoFiles
2014-12-01 00:20:48 +00:00
CORES.add(BUILD['core_path'])
2014-11-30 21:32:14 +00:00
if BUILD['variant_path']
2014-12-01 00:20:48 +00:00
CORES.add(BUILD['variant_path'])
2014-11-30 21:32:14 +00:00
end
2014-11-28 13:18:53 +00:00
ARGV.each_index do |arg|
2014-12-01 00:44:05 +00:00
inName = ARGV[arg]
inName = inName.pathmap("../../%p") unless inName =~ %r|^/|
if inName =~ /\.ino$/
inDir = inName.pathmap("%d")
if !SKETCHES.include?(inDir)
SKETCHES.add(inDir)
end
2014-12-01 00:44:05 +00:00
outName = inName.pathmap("sketch/%n.cpp")
2014-11-28 13:18:53 +00:00
outFile = File.open(outName, 'w')
2014-12-01 00:44:05 +00:00
File.open(inName, 'r') do |ino|
2014-11-28 13:18:53 +00:00
contents = ino.read
# Find protypes:
prototypes = contents.dup
# - Strip comments, quoted strings, and preprocessor directives
2024-10-14 23:37:02 +00:00
prototypes.gsub!(%r{'(?:\\'|[^'])+'|"(?:\\"|[^"])*"|//.*?$|/\*.*?\*/|^\s*?#.*?$}m, ' ')
2014-11-28 13:18:53 +00:00
# Collapse braces
2024-10-14 23:37:02 +00:00
while prototypes.sub!(/(\{)([^{}]+|\{[^{}]*\})/m, '\1') do
2014-11-28 13:18:53 +00:00
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)
2014-11-28 23:35:46 +00:00
proto << p+";\n" unless existingProto[p]
2014-11-28 13:18:53 +00:00
}
contents.each_line do |line|
2024-10-14 23:37:02 +00:00
if line =~ %r{^\s*#include\s+[<"](.*)[">]\s*(#.*|/\*.*?\*/\s*|//.*)?$}
2014-11-28 13:18:53 +00:00
addLibrary($1)
end
end
2014-12-22 05:58:45 +00:00
%r{(?<preamble>(?:\s+|//.*?$|/\*.*?\*/)*)(?<rest>.*)}m =~ contents
2014-11-28 23:35:46 +00:00
outFile.print preamble
outFile.puts '#include "Arduino.h"'
outFile.print proto.join('')
outFile.puts "#line #{1+preamble.count("\n")}"
outFile.print rest
2014-11-28 13:18:53 +00:00
end
outFile.close
2014-12-01 00:44:05 +00:00
FileUtils.touch outName, :mtime => File.mtime(inName)
2014-11-28 13:18:53 +00:00
ARGV[arg] = outName
2014-12-01 00:44:05 +00:00
else
ARGV[arg] = inName
2014-11-28 13:18:53 +00:00
end
end
end
def smashSpaces(s)
return s.gsub(/(\W)\s+(\W)/, '\1\2').gsub(/\s+/, ' ')
end
def addLibrary(header)
2014-11-30 21:32:14 +00:00
lib = HEADERMAP[header]
2014-12-01 00:20:48 +00:00
if lib && !LIBRARIES.include?(lib)
LIBRARIES.add(lib)
2014-11-28 13:18:53 +00:00
end
end
parseArguments
createBuildDirectory
2014-11-30 21:32:14 +00:00
buildHeaderMap
2014-11-28 13:18:53 +00:00
parseInoFiles
2014-12-01 00:44:05 +00:00
File.open("Rakefile", 'w') do |rakeFile|
2014-11-30 22:37:17 +00:00
SOURCES = Rake::FileList.new(ARGV).select {|f| f =~ /\.(c|cpp|cp|cxx|S)$/}
INCLUDES= (SKETCHES+CORES+LIBRARIES).map {|l| " +\n \" -I'#{l}'\""}.join('')
2014-11-28 13:18:53 +00:00
rakeFile.print <<END_RAKE
2014-12-15 01:49:33 +00:00
TOOLCHAIN = "#{BUILD['toolchain']}"
BIN = TOOLCHAIN+"/bin/"
2014-12-22 05:58:45 +00:00
USB = '-DUSB_VID=#{BUILD['usb_vid']} -DUSB_PID=#{BUILD['usb_pid']}'
CC = BIN+'avr-gcc -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=#{BUILD['mcu']} -DF_CPU=#{BUILD['f_cpu']} -MMD '+USB+' -DARDUINO=105'#{INCLUDES}
CCP = BIN+'avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=#{BUILD['mcu']} -DF_CPU=#{BUILD['f_cpu']} -MMD '+USB+' -DARDUINO=105'#{INCLUDES}
2014-12-15 01:49:33 +00:00
LD = BIN+'avr-g++ -Os -Wl,--gc-sections -mmcu=#{BUILD['mcu']}'
AR = BIN+'avr-ar crs'
EEP = BIN+'avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0'
HEX = BIN+'avr-objcopy -O ihex -R .eeprom'
SIZE = BIN+'avr-size'
2014-11-30 21:32:14 +00:00
2014-11-30 22:37:17 +00:00
def compile(dest, extrainc, *src)
2014-11-30 21:32:14 +00:00
directory dest
archive = dest.ext('.a')
sources = Rake::FileList.new(src)
objects = sources.pathmap(dest+"/%n.o")
objects.each_index do |i|
2014-11-30 22:37:17 +00:00
file objects[i] => [sources[i],dest] do
sh "%s %s '%s' -o '%s'" % [sources[i] =~ /.c$/ ? CC : CCP,
extrainc ? "-I '"+extrainc+"'" : '', sources[i], objects[i]]
2014-11-30 21:32:14 +00:00
end
end
file archive => objects do
sh ("%s '%s' " % [AR, archive])+objects.map {|o| "'"+o+"'"}.join(" ")
end
end
2014-11-30 22:37:17 +00:00
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
2014-12-08 04:35:33 +00:00
def compile_core(core,variant=nil)
2014-11-30 22:37:17 +00:00
list = Rake::FileList[core+"/*.{c,cpp,cp,cxx,S}"]
list.add(variant+"/*.{c,cpp,cp,cxx,S}") if variant
compile('core', nil, list)
end
2014-11-30 21:32:14 +00:00
2014-12-01 00:44:05 +00:00
compile('sketch', nil, #{SOURCES.map{|f| "'"+f+"'"}.join(', ')})
2014-12-01 00:20:48 +00:00
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
2014-12-01 03:12:23 +00:00
task :default => ['#{BUILD['project']}.eep', '#{BUILD['project']}.hex'] do
szCmd = "%s '%s' | tail -1 | awk '{print $4}'" % [SIZE, '#{BUILD['project']}.hex']
sz = %x{#{'#'}{szCmd}}.chomp
puts "Binary sketch size: "+sz+" bytes (of a #{BUILD['max_size']} byte maximum)"
end
2014-12-01 00:20:48 +00:00
2014-11-28 13:18:53 +00:00
END_RAKE
end
2014-12-01 00:44:05 +00:00
2014-12-01 02:34:53 +00:00
sh 'rake >& ../build.log'
2014-11-28 13:18:53 +00:00