Skip to content

Commit 74e1ef0

Browse files
authored
Merge pull request #530 from tuna-f1sh/master
ardmk-init - Makefile initialisation and template project utility
2 parents c3fe5dc + a6d979e commit 74e1ef0

File tree

6 files changed

+359
-3
lines changed

6 files changed

+359
-3
lines changed

Arduino.mk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,7 +1443,7 @@ endif
14431443
AVRDUDE_ISP_OPTS = -c $(ISP_PROG) -b $(AVRDUDE_ISP_BAUDRATE)
14441444

14451445
ifndef $(ISP_PORT)
1446-
ifneq ($(strip $(ISP_PROG)),$(filter $(ISP_PROG), usbasp usbtiny gpio linuxgpio avrispmkii dragon_isp dragon_dw))
1446+
ifneq ($(strip $(ISP_PROG)),$(filter $(ISP_PROG), atmelice_isp usbasp usbtiny gpio linuxgpio avrispmkii dragon_isp dragon_dw))
14471447
AVRDUDE_ISP_OPTS += -P $(call get_isp_port)
14481448
endif
14491449
else
@@ -1605,7 +1605,7 @@ ifneq ($(words $(wildcard $(TAGS_FILE))), 0)
16051605
rm -f $(TAGS_FILE)
16061606
endif
16071607
@$(ECHO) "Generating tags for local sources (INO an PDE files as C++): "
1608-
$(CTAGS_CMD) $(TAGS_FILE) --langmap=c++:.ino --langmap=c++:.pde $(LOCAL_SRCS)
1608+
$(CTAGS_CMD) $(TAGS_FILE) --langmap=c++:+.ino.pde $(LOCAL_SRCS)
16091609
ifneq ($(words $(ARDUINO_LIBS)), 0)
16101610
@$(ECHO) "Generating tags for project libraries: "
16111611
$(CTAGS_CMD) $(TAGS_FILE) $(foreach lib, $(ARDUINO_LIBS),$(USER_LIB_PATH)/$(lib)/*)

HISTORY.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ I tried to give credit whenever possible. If I have missed anyone, kindly add it
1414
- Tweak: Move non-standard-related items from CxxFLAGS_STD to CxxFLAGS (issue #523) (https://github.com/sej7278)
1515
- Tweak: Update Windows usage documentation and allow non-relative paths (issue #519) (https://github.com/tuna-f1sh)
1616
- Tweak: Support Cygwin Unix Python and Windows installation on Windows to pass correct port binding. (https://github.com/tuna-f1sh)
17-
- New: Added -fdiagnostics-color to *STD flags (https://github.com/sej7278)
17+
- New: Added -fdiagnostics-color to \*STD flags (https://github.com/sej7278)
1818
- New: Add generation of tags file using ctags, which automatically includes project libs and Arduino core. (https://github.com/tuna-f1sh)
19+
- New: Add template Makefile and project boilerplate initialise script, `ardmk-init`. (https://github.com/tuna-f1sh)
20+
- New: Support atmelice_isp JTAG tool as ISP programmer. (https://github.com/tuna-f1sh)
1921

2022
### 1.6.0 (2017-07-11)
2123
- Fix: Allowed for SparkFun's weird usb pid/vid submenu shenanigans (issue #499). (https://github.com/sej7278)

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,20 @@ all of the examples. The bootstrap script is primarily intended for use by a
428428
continuous integration server, specifically Travis CI. It is not intended for
429429
normal users.
430430

431+
## Makefile Generator and Project Initialisation
432+
433+
`ardmk-init` within the bin/ folder is a utility Python script to create a
434+
Arduino-mk Makefile for a project and also has option to create a traditional *tree*
435+
organization (src, lib, bin). It can be used as with commanline arguments or
436+
prompted - see examples below (append `$ARDMK_DIR/bin/` to command if not on path):
437+
438+
* Run prompted within current working directory: `ardmk-init`
439+
* Create Arduino Uno Makefile (useful within a library example): `ardmk-init -qb uno`
440+
* Create boilerplate Arduino Uno project in current working directory of same
441+
name: `ardmk-init -b uno --quiet --project`
442+
* Create Arduino-mk nano Makefile in current working directory with template .ino: `ardmk-init -b nano -u atmega328 -qtn my-project`
443+
* See `ardmk-init --help` for more.
444+
431445
### Bare-Arduino–Project
432446

433447
If you are planning on using this makefile in a larger/professional project, you might want to take a look at the [Bare-Arduino–Project](https://github.com/WeAreLeka/Bare-Arduino-Project) framework.

ardmk-init.1

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
.TH ARDMK-INIT "1" "Nov 2017" "ardmk-init" "Arduino Makefile Generator"
2+
3+
.SH NAME
4+
ardmk-init - Generate Arduino Makefile environments
5+
6+
.SH SYNOPSIS
7+
.B ardmk-init
8+
[OPTION]...
9+
10+
.SH OPTIONS
11+
.B \-v, \-\-verbose
12+
Print file contents during creation.
13+
14+
.B \-d, \-\-directory
15+
Directory to run generator.
16+
17+
.B \-b, \-\-board
18+
Board tag.
19+
20+
.B \-u, \-\-micro
21+
Microcontroller on board.
22+
23+
.B \-f, \-\-freq
24+
Clock frequency.
25+
26+
.B \-p, \-\-port
27+
Monitor port.
28+
29+
.B \-n, \-\-name
30+
Project name.
31+
32+
.B \-\-cli
33+
Run with user prompts rather than arguments.
34+
35+
.B \-p, \-\-project
36+
Create boilerplate project with src, lib and bin folder structure.
37+
38+
.B \-t, \-\-template
39+
Create bare minimum Arduino source file.
40+
41+
.SH DESCRIPTION
42+
Creates a Makefile and project tree structure from templates.
43+
44+
.SH EXAMPLE
45+
ardmk-init -b uno # create Arduino uno Makefile
46+
.PP
47+
ardmk-init --cli # run with user prompts
48+
.PP
49+
ardmk-init --board uno --project --template --name my-project # create Arduino uno project and template with name "my-project"
50+
51+
.SH BUGS
52+
Problems may reported on the github project page at:
53+
.PP
54+
https://github.com/sudar/Arduino-Makefile
55+
56+
.SH AUTHOR
57+
John Whittington, git@jbrengineering.co.uk
58+
59+
.SH LICENSE
60+
This is under MIT license.

bin/ardmk-init

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
#!/usr/bin/env python
2+
"""
3+
Arduino-mk Makefile and project initialiser
4+
5+
This script can be used in its basic form create a project specific Makefile
6+
for use with Arduino-mk. Addionally, it can be used to create a template
7+
Arduino source file and a traditional boilerplate project file structure.
8+
9+
Example:
10+
* Run prompted within current working directory (requires Clint): `ardmk-init --cli`
11+
* Create Arduino Uno Makefile (useful within a library example): `ardmk-init -b uno`
12+
* Create boilerplate Arduino Uno project in current working directory of same
13+
name: `ardmk-init -b uno --project`
14+
* Create Arduino-mk nano Makefile in current working directory with template .ino:
15+
`ardmk-init -b nano -u atmega328 -tn my-project`
16+
17+
See `armk-init --help` for CLI arguments
18+
"""
19+
20+
from __future__ import print_function
21+
import os
22+
import argparse
23+
24+
## Global Vars
25+
VERSION = "1.1"
26+
ARD_TEMPLATE = "\n\
27+
#include <Arduino.h>\n\
28+
#include <Wire.h>\n\
29+
\n\
30+
\n\
31+
void setup() {\n\
32+
}\n\
33+
\n\
34+
void loop() {\n\
35+
}\n\
36+
"
37+
38+
## Command Parser
39+
PARSER = argparse.ArgumentParser(prog='ardmk-init',
40+
description='Arduino Makefile and boilerplate project generator.\
41+
For use with Ard-Makefile: https://github.com/sudar/Arduino-Makefile.\
42+
Script created by John Whittington https://github.com/tuna-f1sh 2017\
43+
\n\nVersion: ' + VERSION)
44+
PARSER.add_argument('-v', '--verbose', action='store_true',
45+
help="print file contents during creation")
46+
PARSER.add_argument('-d', '--directory', default=os.getcwd(), help='directory to run generator, default cwd')
47+
PARSER.add_argument('-b', '--board', default='uno', help='board tag')
48+
PARSER.add_argument('-u', '--micro', default='AUTO', help='microcontroller on board')
49+
PARSER.add_argument('-f', '--freq', default='AUTO', help='clock frequency')
50+
PARSER.add_argument('-p', '--port', default='AUTO', help='monitor port')
51+
PARSER.add_argument('-n', '--name', default=os.path.basename(os.getcwd()), help='project name')
52+
PARSER.add_argument('--cli', action='store_true', help='run with user prompts (requires "Clint" module), rather than args')
53+
PARSER.add_argument('-P', '--project', action='store_true',
54+
help='create boilerplate project with src, lib and bin folder structure')
55+
PARSER.add_argument('-t', '--template', action='store_true',
56+
help='create bare minimum Arduino source file')
57+
PARSER.add_argument('-V', '--version', action='version', version='%(prog)s '+ VERSION)
58+
ARGS = PARSER.parse_args()
59+
60+
try:
61+
from clint.textui import prompt, validators
62+
except ImportError:
63+
if ARGS.cli:
64+
print("Python module 'clint' is required for running prompted. Install the module or run with arguments only")
65+
quit()
66+
67+
68+
def generate_makefile():
69+
"""
70+
Generate the Makefile content using prompts or parsed arguments
71+
"""
72+
# Header
73+
file_content = "# Generated by ard-make version " + VERSION + "\n\n"
74+
75+
# Basic
76+
if ARGS.cli:
77+
print("Generating Arduino Ard-Makefile project in "
78+
+ os.path.abspath(ARGS.directory))
79+
btag = prompt.query('Board tag?', default='uno')
80+
if btag != 'uno':
81+
bsub = prompt.query('Board sub micro?', default='atmega328')
82+
f_cpu = prompt.query('Board frequency', default='16000000L')
83+
else:
84+
bsub = 'AUTO'
85+
f_cpu = 'AUTO'
86+
monitor_port = prompt.query('Arduino port?', default='AUTO')
87+
else:
88+
btag = ARGS.board
89+
bsub = ARGS.micro
90+
f_cpu = ARGS.freq
91+
monitor_port = ARGS.port
92+
93+
file_content += check_define('BOARD_TAG', btag)
94+
file_content += check_define('BOARD_SUB', bsub)
95+
file_content += check_define('F_CPU', f_cpu)
96+
file_content += check_define('MONITOR_PORT', monitor_port)
97+
98+
# Extended
99+
if ARGS.cli:
100+
if not prompt.yn('Extended options?', default='n'):
101+
if not prompt.yn('Define local folders?', default='n'):
102+
src_dir = prompt.query('Sources folder (Makefile will be created here)?',
103+
default='', validators=[])
104+
userlibs = prompt.query('Library folder (will create if does not exist) - AUTO is Sketchbook directory?',
105+
default='AUTO', validators=[])
106+
obj_dir = prompt.query('Output directory?', default='AUTO', validators=[])
107+
else:
108+
src_dir = ''
109+
userlibs = 'AUTO'
110+
obj_dir = 'AUTO'
111+
boards_txt = prompt.query('Boards file?', default='AUTO')
112+
isp_prog = prompt.query('ISP programmer?', default='atmelice_isp')
113+
isp_port = prompt.query('ISP port?', default='AUTO')
114+
if not prompt.yn('Quiet make?', default='n'):
115+
file_content += "ARDUINO_QUIET = 1\n"
116+
117+
file_content += check_define('ISP_PROG', isp_prog)
118+
file_content += check_define('ISP_PORT', isp_port)
119+
file_content += check_define('BOARDS_TXT', boards_txt)
120+
121+
# Check andd create folders
122+
check_create_folder(src_dir)
123+
check_create_folder(userlibs)
124+
check_create_folder(obj_dir)
125+
126+
# Makefile will be in src_dir so lib and bin must be relative
127+
if src_dir:
128+
userlibs = "../" + userlibs
129+
obj_dir = "../" + obj_dir
130+
131+
file_content += check_define('USER_LIB_PATH', userlibs)
132+
file_content += check_define('OBJDIR', obj_dir)
133+
else:
134+
src_dir = ''
135+
136+
if ARGS.template or not prompt.yn('Create template Arduino source?', default='n'):
137+
source_filename = prompt.query('Name of project?',
138+
default=os.path.basename(os.getcwd()))
139+
if src_dir:
140+
write_template(src_dir + "/" + source_filename)
141+
else:
142+
write_template(source_filename)
143+
file_content += check_define('TARGET', source_filename)
144+
145+
else:
146+
if ARGS.project:
147+
src_dir = 'src'
148+
userlibs = 'lib'
149+
obj_dir = 'bin'
150+
else:
151+
src_dir = ''
152+
userlibs = 'AUTO'
153+
obj_dir = 'AUTO'
154+
155+
# Check andd create folders
156+
check_create_folder(src_dir)
157+
check_create_folder(userlibs)
158+
check_create_folder(obj_dir)
159+
160+
# Makefile will be in src_dir so lib and bin must be relative
161+
if src_dir:
162+
userlibs = "../" + userlibs
163+
obj_dir = "../" + obj_dir
164+
165+
file_content += check_define('USER_LIB_PATH', userlibs)
166+
file_content += check_define('OBJDIR', obj_dir)
167+
168+
if ARGS.project or ARGS.template:
169+
if src_dir:
170+
write_template(src_dir + "/" + ARGS.name)
171+
else:
172+
write_template(ARGS.name)
173+
file_content += check_define('TARGET', ARGS.name)
174+
175+
if not "ARDMK_DIR" in os.environ:
176+
if not ARGS.cli:
177+
print("Warning: ARDMK_DIR environment variable not defined. \
178+
Must be defined for Makefile to work")
179+
else:
180+
ardmk = prompt.query('Arduino Makefile path?',
181+
default='/usr/share/arduino',
182+
validators=[validators.PathValidator()])
183+
ardmk = "ARDMK_DIR := " + ardmk + "\n"
184+
185+
file_content += "\ninclude $(ARDMK_DIR)/Arduino.mk"
186+
187+
# Add forward slash if source directory exists
188+
if src_dir:
189+
write_to_makefile(file_content, (src_dir + "/"))
190+
else:
191+
write_to_makefile(file_content, "")
192+
193+
return file_content
194+
195+
def write_to_makefile(file_content, path):
196+
"""
197+
Write the Makefile file
198+
"""
199+
makefile = open(path + "Makefile", 'w')
200+
print("Writing Makefile...")
201+
if ARGS.verbose:
202+
print(file_content)
203+
makefile.write(file_content)
204+
makefile.close()
205+
206+
def write_template(filename):
207+
"""
208+
Write template Arduino .ino source
209+
"""
210+
print("Writing " + os.path.abspath(filename) + ".ino...")
211+
if os.path.isfile(filename + '.ino'):
212+
if not ARGS.cli:
213+
print(filename + '.ino' + ' already exists! Stopping.')
214+
return
215+
print(filename + '.ino' + ' already exists! Overwrite?')
216+
if prompt.yn('Continue?', default='n'):
217+
return
218+
src = open((filename + ".ino"), 'w')
219+
if ARGS.verbose:
220+
print(ARD_TEMPLATE)
221+
src.write("/* Project: " + filename + " */\n" + ARD_TEMPLATE)
222+
src.close()
223+
224+
def check_create_folder(folder):
225+
"""
226+
Check if folder exists and make it if it doesn't and hasn't been set to AUTO
227+
"""
228+
if folder and not folder == 'AUTO':
229+
if not os.path.exists(folder):
230+
print("Creating " + os.path.abspath(folder) + " folder")
231+
os.makedirs(folder)
232+
233+
def check_define(define, user):
234+
"""
235+
Check whether user has set define and return Makefile formatted string if they have
236+
"""
237+
# Return is empty unless user has passed value
238+
string = ""
239+
240+
# Set define only if not empty or set to AUTO
241+
if user and not user == 'AUTO':
242+
string = define + " = " + user + "\n"
243+
244+
return string
245+
246+
def check_args():
247+
"""
248+
Check input args will work with Makefile
249+
"""
250+
# Micro should be defined for non uno boards
251+
if ARGS.board != 'uno' and ARGS.micro == 'AUTO':
252+
print('\n!!! Warning: --micro should be defined and not left AUTO for non-Uno boards\n')
253+
254+
255+
if __name__ == '__main__':
256+
# Create directory if not exist
257+
check_create_folder(ARGS.directory)
258+
# Check input args
259+
check_args()
260+
# Change to dir so all commands are run relative
261+
os.chdir(ARGS.directory)
262+
if os.path.isfile('Makefile'):
263+
if not ARGS.cli:
264+
print('Makefile in ' + os.path.abspath(ARGS.directory)
265+
+ ' already exists! Please remove before generating. Stopping.')
266+
quit()
267+
268+
# Confirm with user if not quiet mode
269+
print('Makefile in ' + os.path.abspath(ARGS.directory)
270+
+ ' already exists! Overwrite?')
271+
if prompt.yn('Continue?', default='n'):
272+
quit()
273+
# Run it
274+
generate_makefile()

0 commit comments

Comments
 (0)