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