Commit | Line | Data |
---|---|---|
29089d0c JM |
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 |