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