added failsafe_set_to and ignore_on_halt to switch module config
[clinton/Smoothieware.git] / Rakefile
1 require 'rake'
2 require 'pathname'
3 require 'fileutils'
4
5 verbose(ENV['verbose'] == '1')
6 DEBUG = ENV['debug'] == '1'
7
8 def pop_path(path)
9 Pathname(path).each_filename.to_a[1..-1]
10 end
11
12 def obj2src(fn, e)
13 File.join('src', pop_path(File.dirname(fn)), File.basename(fn).ext(e))
14 end
15
16 def is_windows?
17 (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
18 end
19
20 # Makefile .d file loader to be used with the import file loader.
21 # this emulates the -include $(DEPFILES) in a Makefile for the generated .d files
22 class DfileLoader
23 include Rake::DSL
24
25 SPACE_MARK = "\0"
26
27 # Load the makefile dependencies in +fn+.
28 def load(fn)
29 return if ! File.exists?(fn)
30 lines = File.read fn
31 lines.gsub!(/\\ /, SPACE_MARK)
32 lines.gsub!(/#[^\n]*\n/m, "")
33 lines.gsub!(/\\\n/, ' ')
34 lines.each_line do |line|
35 process_line(line)
36 end
37 end
38
39 private
40
41 # Process one logical line of makefile data.
42 def process_line(line)
43 file_tasks, args = line.split(':', 2)
44 return if args.nil?
45 dependents = args.split.map { |d| respace(d) }
46 file_tasks.scan(/\S+/) do |file_task|
47 file_task = respace(file_task)
48 file file_task => dependents
49 end
50 end
51
52 def respace(str)
53 str.tr SPACE_MARK, ' '
54 end
55 end
56
57 # Install the handler
58 Rake.application.add_loader('d', DfileLoader.new)
59
60 PROG = 'smoothie'
61
62 DEVICE = 'LPC1768'
63 ARCHITECTURE = 'armv7-m'
64
65 MBED_DIR = './mbed/drop'
66
67 TOOLSBIN = './gcc-arm-none-eabi/bin/arm-none-eabi-'
68 CC = "#{TOOLSBIN}gcc"
69 CCPP = "#{TOOLSBIN}g++"
70 LD = "#{TOOLSBIN}g++"
71 OBJCOPY = "#{TOOLSBIN}objcopy"
72 SIZE = "#{TOOLSBIN}size"
73
74 # include a defaults file if present
75 load 'rakefile.defaults' if File.exists?('rakefile.defaults')
76
77 if DEBUG
78 BUILDTYPE= 'Debug'
79 ENABLE_DEBUG_MONITOR= '0'
80 end
81
82 # Set build type
83 BUILDTYPE= ENV['BUILDTYPE'] || 'Checked' unless defined? BUILDTYPE
84 puts "#{BUILDTYPE} build"
85
86 ENABLE_DEBUG_MONITOR = ENV['ENABLE_DEBUG_MONITOR'] || '0' unless defined? ENABLE_DEBUG_MONITOR
87
88 # set default baud rate
89 DEFAULT_SERIAL_BAUD_RATE= ENV['BAUDRATE'] || '115200' unless defined? DEFAULT_SERIAL_BAUD_RATE
90
91 # set to true to eliminate all the network code
92 NONETWORK= false unless defined? NONETWORK
93
94 # list of modules to exclude, include directory it is in
95 EXCLUDE_MODULES= %w(tools/touchprobe) unless defined? EXCLUDE_MODULES
96
97 # e.g for a CNC machine
98 #EXCLUDE_MODULES = %w(tools/touchprobe tools/laser tools/temperaturecontrol tools/extruder)
99
100 # generate regex of modules to exclude and defines
101 exclude_defines, excludes = EXCLUDE_MODULES.collect { |e| [e.tr('/', '_').upcase, e.sub('/', '\/')] }.transpose
102
103 # see if network is enabled
104 if ENV['NONETWORK'] || NONETWORK
105 nonetwork= true
106 excludes << '\/libs\/Network\/'
107 puts "Excluding Network code"
108 else
109 nonetwork= false
110 end
111
112 SRC = FileList['src/**/*.{c,cpp}'].exclude(/#{excludes.join('|')}/)
113
114 puts "WARNING Excluding modules: #{EXCLUDE_MODULES.join(' ')}" unless exclude_defines.empty?
115
116 OBJDIR = 'OBJ'
117 OBJ = SRC.collect { |fn| File.join(OBJDIR, pop_path(File.dirname(fn)), File.basename(fn).ext('o')) } +
118 %W(#{OBJDIR}/configdefault.o #{OBJDIR}/mbed_custom.o)
119
120 # list of header dependency files generated by compiler
121 DEPFILES = OBJ.collect { |fn| File.join(File.dirname(fn), File.basename(fn).ext('d')) }
122
123 # create destination directories
124 SRC.each do |s|
125 d= File.join(OBJDIR, pop_path(File.dirname(s)))
126 FileUtils.mkdir_p(d) unless Dir.exists?(d)
127 end
128
129 INCLUDE_DIRS = [Dir.glob(['./src/**/', './mri/**/'])].flatten
130 MBED_INCLUDE_DIRS = %W(#{MBED_DIR}/ #{MBED_DIR}/LPC1768/)
131
132 INCLUDE = (INCLUDE_DIRS+MBED_INCLUDE_DIRS).collect { |d| "-I#{d}" }.join(" ")
133
134 if ENABLE_DEBUG_MONITOR == '1'
135 # Can add MRI_UART_BAUD=115200 to next line if GDB fails to connect to MRI.
136 # Tends to happen on some Linux distros but not Windows and OS X.
137 MRI_UART = 'MRI_UART_0'
138 MRI_BREAK_ON_INIT = 1 unless defined? MRI_BREAK_ON_INIT
139 else
140 MRI_UART = 'MRI_UART_0 MRI_UART_SHARE'
141 MRI_BREAK_ON_INIT = 0 unless defined? MRI_BREAK_ON_INIT
142 end
143
144 # Configure MRI variables based on BUILD_TYPE build type variable.
145 case BUILDTYPE.downcase
146 when 'release'
147 OPTIMIZATION = 2
148 MRI_ENABLE = 0
149 MRI_SEMIHOST_STDIO = 0 unless defined? MRI_SEMIHOST_STDIO
150 when 'debug'
151 OPTIMIZATION = 0
152 MRI_ENABLE = 1
153 MRI_SEMIHOST_STDIO = 1 unless defined? MRI_SEMIHOST_STDIO
154 when 'checked'
155 OPTIMIZATION = 2
156 MRI_ENABLE = 1
157 MRI_SEMIHOST_STDIO = 1 unless defined? MRI_SEMIHOST_STDIO
158 end
159
160 MRI_ENABLE = 1 unless defined? MRI_ENABLE # set to 0 to disable MRI
161 MRI_LIB = MRI_ENABLE == 1 ? './mri/mri.ar' : ''
162 MBED_LIB = "#{MBED_DIR}/LPC1768/GCC_ARM/libmbed.a"
163
164 SYS_LIBS = '-lstdc++_s -lsupc++_s -lm -lgcc -lc_s -lgcc -lc_s -lnosys'
165 LIBS = [MBED_LIB, SYS_LIBS, MRI_LIB].join(' ')
166
167 MRI_DEFINES = %W(-DMRI_ENABLE=#{MRI_ENABLE} -DMRI_INIT_PARAMETERS='"#{MRI_UART}"' -DMRI_BREAK_ON_INIT=#{MRI_BREAK_ON_INIT} -DMRI_SEMIHOST_STDIO=#{MRI_SEMIHOST_STDIO})
168
169 defines = %w(-DCHECKSUM_USE_CPP -D__LPC17XX__ -DTARGET_LPC1768 -DWRITE_BUFFER_DISABLE=0 -DSTACK_SIZE=3072 -DCHECKSUM_USE_CPP)
170 defines += exclude_defines.collect{|d| "-DNO_#{d}"}
171 defines += MRI_DEFINES
172 defines << "-DDEFAULT_SERIAL_BAUD_RATE=#{DEFAULT_SERIAL_BAUD_RATE}"
173 defines << '-DDEBUG' if OPTIMIZATION == 0
174 defines << '-DNONETWORK' if nonetwork
175
176 DEFINES= defines.join(' ')
177
178 # Compiler flags used to enable creation of header dependencies.
179 DEPFLAGS = '-MMD '
180 CFLAGS = DEPFLAGS + "-Wall -Wextra -Wno-unused-parameter -Wcast-align -Wpointer-arith -Wredundant-decls -Wcast-qual -Wcast-align -O#{OPTIMIZATION} -g3 -mcpu=cortex-m3 -mthumb -mthumb-interwork -ffunction-sections -fdata-sections -fno-exceptions -fno-delete-null-pointer-checks"
181 CPPFLAGS = CFLAGS + ' -fno-rtti -std=gnu++11'
182
183 MRI_WRAPS = MRI_ENABLE == 1 ? ',--wrap=_read,--wrap=_write,--wrap=semihost_connected' : ''
184
185 # Linker script to be used. Indicates what code should be placed where in memory.
186 LSCRIPT = "#{MBED_DIR}/LPC1768/GCC_ARM/LPC1768.ld"
187 LDFLAGS = "-mcpu=cortex-m3 -mthumb -specs=./build/startfile.spec" +
188 " -Wl,-Map=#{OBJDIR}/smoothie.map,--cref,--gc-sections,--wrap=_isatty,--wrap=malloc,--wrap=realloc,--wrap=free" +
189 MRI_WRAPS +
190 " -T#{LSCRIPT}" +
191 " -u _scanf_float -u _printf_float"
192
193 HTTPD_FSDATA = './src/libs/Network/uip/webserver/httpd-fsdata2.h'
194
195 # tasks
196
197 # generate the header dependencies if they exist
198 import(*DEPFILES)
199
200 task :clean do
201 FileUtils.rm_rf(OBJDIR)
202 end
203
204 task :realclean => [:clean] do
205 sh "cd ./mbed;make clean"
206 end
207
208 desc "Build the built-in web pages"
209 task :webui => [HTTPD_FSDATA]
210
211 task :default => [:build]
212
213 task :build => [MBED_LIB, :version, "#{PROG}.bin", :size]
214
215 task :version do
216 if is_windows?
217 VERSION = ' -D__GITVERSIONSTRING__=\"place-holder\"'
218 else
219 v1= `git symbolic-ref HEAD 2> /dev/null`
220 v2= `git log --pretty=format:%h -1`
221 VERSION = ' -D__GITVERSIONSTRING__=\"' + "#{v1[11..-1].chomp}-#{v2}".chomp + '\"'
222 FileUtils.touch './src/version.cpp' # we want it compiled everytime
223 end
224 end
225
226 desc "Upload via DFU"
227 task :upload do
228 sh "dfu-util -R -d 1d50:6015 -D #{OBJDIR}/#{PROG}.bin"
229 end
230
231 task :size do
232 sh "#{SIZE} #{OBJDIR}/#{PROG}.elf"
233 end
234
235 # build internal web page
236 WEB_SOURCE_FILES= FileList['./src/libs/Network/uip/webserver/httpd-fs-src/**/*']
237 WEBDIR = './src/libs/Network/uip/webserver/httpd-fs'
238 file HTTPD_FSDATA => WEB_SOURCE_FILES do
239 FileUtils.rm_rf WEBDIR
240 FileUtils.mkdir WEBDIR
241 FileUtils.cp WEB_SOURCE_FILES, WEBDIR
242 # TODO minify some files
243 # sh 'java -jar yuicompressor-2.4.8.jar file -o file'
244 sh 'cd ./src/libs/Network/uip/webserver; perl makefsdata.pl'
245 sh 'cd ./src; make'
246 end
247
248 file MBED_LIB do
249 puts "Building Mbed Using Make"
250 sh "cd ./mbed;make all"
251 end
252
253 file "#{OBJDIR}/mbed_custom.o" => ['./build/mbed_custom.cpp'] do |t|
254 puts "Compiling #{t.source}"
255 sh "#{CCPP} #{CPPFLAGS} #{INCLUDE} #{DEFINES} -c -o #{t.name} #{t.prerequisites[0]}"
256 end
257
258 file "#{OBJDIR}/configdefault.o" => 'src/config.default' do |t|
259 sh "cd ./src; ../#{OBJCOPY} -I binary -O elf32-littlearm -B arm --readonly-text --rename-section .data=.rodata.configdefault config.default ../#{OBJDIR}/configdefault.o"
260 end
261
262 file "#{PROG}.bin" => ["#{PROG}.elf"] do
263 sh "#{OBJCOPY} -O binary #{OBJDIR}/#{PROG}.elf #{OBJDIR}/#{PROG}.bin"
264 end
265
266 file "#{PROG}.elf" => OBJ do |t|
267 puts "Linking #{t.source}"
268 sh "#{LD} #{LDFLAGS} #{OBJ} #{LIBS} -o #{OBJDIR}/#{t.name}"
269 end
270
271 #arm-none-eabi-objcopy -R .stack -O ihex ../LPC1768/main.elf ../LPC1768/main.hex
272 #arm-none-eabi-objdump -d -f -M reg-names-std --demangle ../LPC1768/main.elf >../LPC1768/main.disasm
273
274 rule '.o' => lambda{ |objfile| obj2src(objfile, 'cpp') } do |t|
275 puts "Compiling #{t.source}"
276 sh "#{CCPP} #{CPPFLAGS} #{INCLUDE} #{DEFINES} #{VERSION} -c -o #{t.name} #{t.source}"
277 end
278
279 rule '.o' => lambda{ |objfile| obj2src(objfile, 'c') } do |t|
280 puts "Compiling #{t.source}"
281 sh "#{CC} #{CFLAGS} #{INCLUDE} #{DEFINES} #{VERSION} -c -o #{t.name} #{t.source}"
282 end
283