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