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