mkduino 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ mkduino
2
+ =======
3
+
4
+ Ruby script for generating a GNU Automake style makefile system for your arduino projects
5
+
6
+ You'll probably need to use Fedora 19 to have this work out of the box. Pull requests or
7
+ github issues for other distributions / systems will thoughtfully considered.
8
+
9
+ If there's enough interest, I'll add some command line switches and more dynamic configuration
10
+ of he environment. It would probably be simple to find the arduino environment rather than
11
+ hardcoding it. Also, doing a `git init` and adding certain files to the repo would be really
12
+ handy for someone that uses this regularly. Again - add github issues or send pull requests...
13
+
14
+ ## Installation
15
+
16
+ `gem install mkduino`
17
+
18
+ ## Usage
19
+ ========
20
+ Go to the directory where your source code is(or should be):
21
+
22
+ ```
23
+ mkduino
24
+ ./autogen.sh
25
+ ./configure --host=avr
26
+ make
27
+ make upload
28
+ ```
29
+
30
+ ## Files Generated
31
+ ==================
32
+
33
+ ### src/main.cpp
34
+ This cpp file is generated if there are no `.cpp`, `.hpp`, `.c` or `.h` files found when mkduino is run.
35
+ It's a simple file like the one generated from the IDE.
36
+
37
+ ### Makefile.am
38
+ This is where most of the configuration for automake ends up. This Automake file is
39
+ initially configured for an Arduino Pro Mini, but there are some variables that can
40
+ be changed in this file to customize it. Any changes made to this file will be
41
+ automatically picked up by make on your next make invocation.
42
+
43
+ * `ARDUINO_VERSION=-DARDUINO=105`
44
+ Define of what version of the Arduino libaries you're using.
45
+ * `ARDUINO_INSTALL=/usr/share/arduino/hardware/arduino`
46
+ Where the Arduino library stuff is installed. This is the default on a Fedora system
47
+ * `MCU=atmega328p`
48
+ Change this if you have a different supported ATMEL chip.
49
+ For instance set it to `MCU=atmega1280` for an ATMEL atmega1280 chip
50
+ * `ARDUINO_VARIANTS=$(ARDUINO_INSTALL)/variants/standard`
51
+ You many need to change `standard` to something else for mega 1280 and 2560 chips
52
+ * `AVRDUDE_PORT=/dev/ttyUSB0`
53
+ The port that `make upload` will try to send the code to.
54
+ * `AVRDUDE_PROGRAMMER = arduino*`
55
+ The `avrdude` programmer type.
56
+ Check the [`avrdude` documentation](http://www.nongnu.org/avrdude/user-manual)
57
+
58
+ ### configure.ac
59
+ There's not much to see here. This file is customized with the project name and that's about it.
60
+
61
+ ### autogen.sh
62
+ Execute this file after running `mkduino`. This file isn't customized for each project - it's the same every time.
63
+
64
+ ### README, NEWS, AUTHORS, ChangeLog, config/config.h and m4/
65
+ Standard files and directories for GNU Automake. Just created, nothing is in them.
66
+
67
+ ## Why?
68
+ ======
69
+ Every time I run the Arduino IDE I struggle to have my hands unlearn the `emacs` keybindings
70
+ so I can do some little thing. I got really tired of it and made myself a makefile.
71
+
72
+ After bragging about my makefile prowess to my friends, they all wanted to ditch the Arduino IDE.
73
+ I was embarrassed of my initial makefile, so I decided to make an environment builder for Arduino.
74
+ My initial try at this projects included downloading all of the tools (yes, even gcc), building
75
+ it all very similarly to `rvm`. That proved to be a project much too big for the typical Arduino
76
+ hacker to undertake, so I quickly regrouped and hacked out this ruby script to make an automake
77
+ environment.
78
+
79
+ Hopefully this enables you to use your environment of choice for Arduino hacking.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/mkduino ADDED
@@ -0,0 +1,63 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # mkduino.rb
4
+ # Ruby script for generating a GNU Automake (ish)
5
+ # environment for Arduino development
6
+ #
7
+ # (C) Copyright 2013,2014
8
+ # David H. Wilkins <dwilkins@conecuh.com>
9
+ #
10
+ # This program is free software; you can redistribute it and/or
11
+ # modify it under the terms of the GNU General Public License as
12
+ # published by the Free Software Foundation; either version 2 of
13
+ # the License, or (at your option) any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the GNU General Public License
21
+ # along with this program; if not, write to the Free Software
22
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23
+ # MA 02111-1307 USA
24
+ #
25
+
26
+ require "mkduino"
27
+
28
+ ma = Mkduino::MakefileAm.new
29
+ ma.find_arduino_libraries '/usr/share/arduino/libraries'
30
+ ma.find_arduino_libraries '/usr/share/arduino/hardware/arduino/cores'
31
+ ma.find_source_files
32
+ ca = Mkduino::ConfigureAc.new ma
33
+ as = Mkduino::AutogenSh.new
34
+ puts ma.to_yaml
35
+
36
+ ##
37
+ # Output the Makefile.am file withe the needed variable replacements
38
+ ##
39
+ ma.write_makefile_am
40
+ ##
41
+ # Output the configure.ac - requires a few things from Makefile.am
42
+ ##
43
+ ca.write_configure_ac
44
+ ##
45
+ # Finally write the autogen.sh - no replacements there
46
+ ##
47
+ as.write_autogen_sh
48
+
49
+ #
50
+ # A few shell commands required to make it all tidy
51
+ #
52
+ `chmod +x autogen.sh`
53
+ `mkdir m4` unless Dir.exist?('m4')
54
+ `mkdir config` unless Dir.exist?('config')
55
+ `touch config/config.h`
56
+ `touch NEWS`
57
+ `touch README`
58
+ `touch AUTHORS`
59
+ `touch ChangeLog`
60
+
61
+ puts "*******************************"
62
+ puts "** now run ./autogen.sh **"
63
+ puts "*******************************"
data/lib/mkduino.rb ADDED
@@ -0,0 +1,407 @@
1
+ require "mkduino/version"
2
+ require 'yaml'
3
+ require 'find'
4
+ require 'pathname'
5
+ require 'fileutils'
6
+
7
+ include FileUtils
8
+
9
+ module Mkduino
10
+ #
11
+ # Represents the files needed for a particular arduino library
12
+ #
13
+ class ArduinoLibrary
14
+ def initialize name
15
+ @library_sources = []
16
+ @name = name
17
+ @library_includes = []
18
+ end
19
+
20
+ def name
21
+ return @name.downcase
22
+ end
23
+
24
+ def add_source_file(file)
25
+ pn = Pathname.new(file)
26
+ puts "!! ******** File #{file} not found ******** " unless pn.exist?
27
+ @library_sources << file
28
+ end
29
+ def add_include_path file
30
+ pn = Pathname.new(file)
31
+ puts "!! ******** File #{file} not found ******** " unless pn.exist?
32
+ include_dir = pn.file? ? pn.dirname : file
33
+ puts "Add include for #{file} = #{include_dir}"
34
+
35
+ @library_includes << include_dir.to_s unless @library_includes.include? include_dir.to_s
36
+ end
37
+
38
+ def linker_name
39
+ self.name
40
+ end
41
+
42
+ def library_name
43
+ "lib#{self.name}.a"
44
+ end
45
+
46
+ def makefile_am_output
47
+ output = <<LIBRARY_OUTPUT
48
+ lib#{self.name}_a_CFLAGS=-Wall -I$(ARDUINO_VARIANTS) $(ARDUINO_COMMON_INCLUDES) $(lib#{self.name}_a_INCLUDES) -Wl,--gc-sections -ffunction-sections -fdata-sections -mmcu=$(MCU) $(F_CPU) $(ARDUINO_VERSION) -D__AVR_LIBC_DEPRECATED_ENABLE__
49
+ lib#{self.name}_a_CXXFLAGS=-Wall -I$(ARDUINO_VARIANTS) $(ARDUINO_COMMON_INCLUDES) $(lib#{self.name}_a_INCLUDES) -Wl,--gc-sections -ffunction-sections -fdata-sections -mmcu=$(MCU) $(F_CPU) $(ARDUINO_VERSION) -D__AVR_LIBC_DEPRECATED_ENABLE__
50
+ lib#{self.name}_a_SOURCES = #{@library_sources.join("\\\n ")}
51
+ lib#{self.name}_a_INCLUDES = -I#{@library_includes.join("\\\n -I")}
52
+ LIBRARY_OUTPUT
53
+ output
54
+ end
55
+ end
56
+
57
+ #
58
+ # Class that keeps up with the stuff needed for the Makefile.am file
59
+ # this is most of the stuff needed to generate the automake stuff
60
+ #
61
+
62
+ class MakefileAm
63
+ attr_accessor :source_files, :header_files, :arduino_sources
64
+ attr_accessor :project_name, :project_author, :project_dir
65
+ attr_accessor :project_includes
66
+ # future stuff
67
+ attr_accessor :git_project
68
+ attr_accessor :board, :common_includes
69
+
70
+ def initialize
71
+ @project_dir = Dir.pwd
72
+ @project_name = File.basename @project_dir
73
+ @project_name.tr!('.','_')
74
+ @source_files = []
75
+ @header_files = []
76
+ @project_includes = []
77
+ @arduino_sources = []
78
+ @arduino_includes = []
79
+ @arduino_libraries = []
80
+ @project_author = {}
81
+ @git_project = nil
82
+ @common_libraries = ['arduino', 'spi','wire']
83
+ @libraries_to_skip = {
84
+ 'standard' => ['Esplora','GSM','Robot_Control','Robot_Motor','TFT','robot']
85
+ }
86
+ @board='standard'
87
+ @project_author[:username] = ENV['USERNAME']
88
+ git_exists = `which git`.chomp
89
+ if git_exists && git_exists.length > 0
90
+ @project_author[:name] = `git config --get user.name`.chomp
91
+ @project_author[:email] = `git config --get user.email`.chomp
92
+ @git_project = `git remote show -n origin 2> /dev/null | grep 'Fetch URL:' | cut -f 5 -d ' '`.chomp
93
+ else
94
+ @project_author[:name] = @project_author[:username]
95
+ @project_author[:email]= @project_author[:username]
96
+ @git_project = "no_git_project"
97
+ end
98
+ end
99
+
100
+ #
101
+ # Add a source file that we found in this directory
102
+ #
103
+ def add_source_file(file)
104
+ @source_files << "../" + Pathname.new(file).relative_path_from(Pathname.new(@project_dir)).to_s
105
+ end
106
+ def add_header_file(file)
107
+ @header_files << "../" + Pathname.new(file).relative_path_from(Pathname.new(@project_dir)).to_s
108
+ end
109
+
110
+ def add_include_path file
111
+ pn = Pathname.new(file)
112
+ puts "!! ******** File #{file} not found ******** " unless pn.exist?
113
+ include_dir = pn.file? ? pn.dirname : file
114
+ puts "Add include for #{file} = #{include_dir}"
115
+
116
+ @project_includes << include_dir.to_s unless @project_includes.include? include_dir.to_s
117
+ end
118
+
119
+
120
+ #
121
+ # As libraries are found, add them to our collection
122
+ # if they're not already there
123
+ #
124
+ def add_arduino_library library
125
+ @arduino_libraries << library if !arduino_library library
126
+ end
127
+
128
+ #
129
+ # fetch a library from our collection - nil if not there
130
+ #
131
+
132
+ def arduino_library library
133
+ @arduino_libraries.each do |l|
134
+ return l if l.name == library
135
+ end
136
+ nil
137
+ end
138
+
139
+ #
140
+ # output the Makefile.am macro needed for some include
141
+ # files from libraries that are apparently always needed
142
+ #
143
+ def common_includes
144
+ @arduino_libraries.collect do |l|
145
+ @common_libraries.include?(l.name) ? "$(lib#{l.name}_a_INCLUDES)" : nil
146
+ end.compact.join(' ')
147
+ end
148
+
149
+
150
+ def source_file_pattern
151
+ /\.([c])(pp|)$/
152
+ end
153
+
154
+ def header_file_pattern
155
+ /\.([h])(pp|)$/
156
+ end
157
+
158
+ #
159
+ # output a list of all the libraries that are needed here
160
+ # for Makefile.am. The project will depend on these
161
+ #
162
+ def arduino_library_names
163
+ @arduino_libraries.collect do |l|
164
+ l.library_name
165
+ end
166
+ end
167
+
168
+ #
169
+ # return the linker entries for all of the libraries that we
170
+ # know about
171
+ #
172
+ def arduino_linker_entries
173
+ @arduino_libraries.collect do |l|
174
+ "-l#{l.linker_name}"
175
+ end
176
+ end
177
+
178
+ #
179
+ # after finding all of the Arduino libraries, go through each
180
+ # one of them asking them to output themselves.
181
+ #
182
+
183
+ def output_arduino_libraries
184
+ output = @arduino_libraries.collect do |l|
185
+ l.makefile_am_output
186
+ end.join("\n")
187
+ #
188
+ # After all of the library compile lines are output, output
189
+ # a comprehensive list of all of the include directories associated
190
+ # with the libraries. Used for the source project
191
+ #
192
+ output += "\nLIBRARY_INCLUDES="
193
+ output += @arduino_libraries.collect do |l|
194
+ "$(lib#{l.name}_a_INCLUDES)"
195
+ end.join(' ')
196
+ end
197
+
198
+ def find_arduino_libraries libraries_dir
199
+ lib = nil
200
+ Find.find(libraries_dir) do |path|
201
+ if FileTest.directory?(path)
202
+ if File.basename(path)[0] == ?. || File.basename(path) == 'examples' ||
203
+ (@libraries_to_skip[@board] && @libraries_to_skip[@board].include?(File.basename(path)) )
204
+ Find.prune # Don't look any further into this directory.
205
+ else
206
+ if File.dirname(path) == libraries_dir
207
+ lib_name = path.split('/')[-1]
208
+ lib = arduino_library(lib_name) || ArduinoLibrary.new(lib_name)
209
+ add_arduino_library lib
210
+ end
211
+ next
212
+ end
213
+ elsif path =~ source_file_pattern
214
+ lib.add_source_file path
215
+ elsif path =~ header_file_pattern
216
+ lib.add_include_path path
217
+ end
218
+ end
219
+ end
220
+
221
+ def find_source_files
222
+ #
223
+ # Root around for some source file
224
+ # and add them to the Makefile.am
225
+ #
226
+ Find.find(Dir.pwd) do |path|
227
+ if FileTest.directory?(path)
228
+ if File.basename(path)[0] == ?.
229
+ Find.prune # Don't look any further into this directory.
230
+ else
231
+ next
232
+ end
233
+ elsif path =~ source_file_pattern
234
+ add_source_file path
235
+ elsif path =~ header_file_pattern
236
+ add_header_file path
237
+ add_include_path path
238
+
239
+ end
240
+ end
241
+
242
+ #
243
+ # If no source files were found, make
244
+ # the src/ directory and put in a
245
+ # sample main.cpp file
246
+ #
247
+ if source_files.length < 1
248
+ `mkdir src` unless Dir.exist?('src')
249
+ File.open('src/main.cpp',"w") do |f|
250
+ f.puts <<-MAIN_CPP
251
+ #include <Arduino.h>
252
+
253
+ extern "C" void __cxa_pure_virtual(void) {
254
+ while(1);
255
+ }
256
+
257
+ void setup() {
258
+ Serial.begin(115200);
259
+ Serial.println("Startup...");
260
+ }
261
+
262
+ void loop() {
263
+ }
264
+
265
+
266
+
267
+ int main(void)
268
+ {
269
+ init();
270
+ setup();
271
+ for (;;){
272
+ loop();
273
+ }
274
+ return 0;
275
+ }
276
+ MAIN_CPP
277
+ end
278
+ add_source_file project_dir + '/src/main.cpp'
279
+ end
280
+ end
281
+
282
+
283
+
284
+
285
+ def write_makefile_am
286
+ File.open('Makefile.am',"w") do |f|
287
+ f.puts <<-MAKEFILE_AM
288
+ ## Process this file with automake to produce Makefile.in
289
+ bin_PROGRAMS=#{self.project_name}
290
+ # MCU=atmega1280
291
+ MCU=atmega328p
292
+ F_CPU=-DF_CPU=16000000
293
+ ARDUINO_VERSION=-DARDUINO=105
294
+ ARDUINO_INSTALL=/usr/share/arduino/hardware/arduino
295
+ ARDUINO_CORES=$(ARDUINO_INSTALL)/cores/arduino
296
+ ARDUINO_VARIANTS=$(ARDUINO_INSTALL)/variants/#{self.board}
297
+ ARDUINO_COMMON_INCLUDES=#{self.common_includes}
298
+ ARDUINO_INCLUDE_PATH=-I$(ARDUINO_VARIANTS) $(LIBRARY_INCLUDES)
299
+ nodist_#{self.project_name}_SOURCES=#{self.source_files.join(' ')}
300
+
301
+ #{self.project_name}_CFLAGS=-Wall $(#{self.project_name}_INCLUDES) $(ARDUINO_INCLUDE_PATH) -Wl,--gc-sections -ffunction-sections -fdata-sections -gstabs -mmcu=$(MCU) $(F_CPU) $(ARDUINO_VERSION) -D__AVR_LIBC_DEPRECATED_ENABLE__
302
+ #{self.project_name}_CXXFLAGS=-Wall $(#{self.project_name}_INCLUDES) $(ARDUINO_INCLUDE_PATH) -Wl,--gc-sections -ffunction-sections -fdata-sections -gstabs -mmcu=$(MCU) $(F_CPU) $(ARDUINO_VERSION) -D__AVR_LIBC_DEPRECATED_ENABLE__
303
+ #{self.project_name}_LDFLAGS=-L.
304
+ #{self.project_name}_LDADD=#{self.arduino_linker_entries.join(' ')} -lm
305
+ #{self.project_name}_INCLUDES=-I#{self.project_includes.join("\\\n -I")}
306
+
307
+ lib_LIBRARIES=#{self.arduino_library_names.join(' ')}
308
+ #{self.output_arduino_libraries}
309
+
310
+
311
+ AM_LDFLAGS=
312
+ AM_CXXFLAGS=-g0 -Os
313
+ AM_CFLAGS=-g0 -Os
314
+ VPATH=/usr/share/arduino/hardware/arduino/cores/arduino
315
+
316
+ # AVRDUDE_PORT=/dev/ttyACM0
317
+ AVRDUDE_PORT=/dev/ttyUSB0
318
+ AVRDUDE_PROGRAMMER = arduino
319
+ # UPLOAD_RATE = 115200
320
+ UPLOAD_RATE = 57600
321
+ FORMAT=ihex
322
+
323
+ AVRDUDE_WRITE_FLASH = -U flash:w:$(bin_PROGRAMS).hex
324
+ AVRDUDE_FLAGS = -q -D -C/etc/avrdude/avrdude.conf -p$(MCU) -P$(AVRDUDE_PORT) -c$(AVRDUDE_PROGRAMMER) -b$(UPLOAD_RATE)
325
+
326
+
327
+ .PHONY: upload
328
+ upload: all-am
329
+ $(OBJCOPY) -S -O $(FORMAT) $(bin_PROGRAMS) $(bin_PROGRAMS).hex
330
+ $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
331
+ MAKEFILE_AM
332
+
333
+ end
334
+ end
335
+
336
+ end
337
+
338
+
339
+ class ConfigureAc
340
+ attr_accessor :makefile_am
341
+ def initialize makefile_am
342
+ @makefile_am = makefile_am
343
+ end
344
+ def write_configure_ac
345
+ ##
346
+ # Output the configure.ac file
347
+ ##
348
+ File.open('configure.ac',"w") do |f|
349
+ f.puts <<-CONFIGURE_AC
350
+ dnl Process this file with autoconf to produce a configure script.")
351
+ AC_INIT([#{makefile_am.project_name}], [1.0])
352
+ dnl AC_CONFIG_SRCDIR( [ Makefile.am ] )
353
+ AM_INIT_AUTOMAKE
354
+ AM_CONFIG_HEADER(config.h)
355
+ dnl AM_CONFIG_HEADER(config.h)
356
+ dnl Checks for programs.
357
+ AC_PROG_CC( avr-gcc )
358
+ AC_PROG_CXX( avr-g++ )
359
+ AC_PROG_RANLIB( avr-ranlib )
360
+ AC_PATH_PROG(OBJCOPY, avr-objcopy)
361
+ AC_PATH_PROG(AVRDUDE, avrdude)
362
+
363
+ AC_ISC_POSIX
364
+
365
+ dnl Checks for libraries.
366
+
367
+ dnl Checks for header files.
368
+ AC_HAVE_HEADERS( Arduino.h )
369
+
370
+ dnl Checks for library functions.
371
+
372
+ dnl Check for st_blksize in struct stat
373
+
374
+
375
+ dnl internationalization macros
376
+ AC_OUTPUT([Makefile])
377
+
378
+ CONFIGURE_AC
379
+
380
+ end
381
+ end
382
+ end
383
+
384
+ class AutogenSh
385
+ def write_autogen_sh
386
+ File.open('autogen.sh',"w") do |f|
387
+ f.puts <<-AUTOGEN_SH
388
+ #!/bin/sh
389
+ if [ -e 'Makefile.am' ] ; then
390
+ echo "Makefile.am Exists - reconfiguring..."
391
+ autoreconf --force --install -I config -I m4
392
+ echo
393
+ echo
394
+ echo "************************************"
395
+ echo "** Now run mkdir build ; cd build ; ../configure --host=avr **"
396
+ echo "************************************"
397
+ exit
398
+ fi
399
+ echo "Lets get your project started!"
400
+
401
+ echo '## Process this file with automake to produce Makefile.in' >> Makefile.am
402
+ echo No Makefile.am
403
+ AUTOGEN_SH
404
+ end
405
+ end
406
+ end
407
+ end