mkduino 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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