Skip to content

Instantly share code, notes, and snippets.

@twpayne
Created March 21, 2015 15:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save twpayne/bdea90725d3d9b6bba1c to your computer and use it in GitHub Desktop.
Save twpayne/bdea90725d3d9b6bba1c to your computer and use it in GitHub Desktop.
Rough-and-ready approximation to Arduino's multi-file sketch assembly process
#!/usr/bin/python
import glob
import re
import os
import sys
def assemble_paths(paths):
"""Assemble multiple files together into a main sketch. paths is a list
of paths to individual files, the first element is assumed to be the
main file. The assembled file is written to sys.stdout."""
# find all prototypes in all input files
prototypes = []
for path in paths:
with open(path) as f:
m = re.findall(
r"""^(
(?:\s*[a-z_\d]+){1,2} # return type
\s+[a-z_\d]+\s* # name of prototype
\([a-z_,\.\*\&\[\]\s\d]*\) # args
)\s*\{ # must end with {
""",
f.read(),
re.X | re.M | re.I
)
prototypes.extend(p.strip() for p in m)
# write output file header
sys.stdout.write('#include "Arduino.h"\n')
# copy the main file, up to the first non comment/preprocessor/blank line
f = open(paths[0])
in_comment = False
for line in f:
if in_comment:
if line.find('*/') != -1:
in_comment = False
else:
if line.find('/*') != -1 and line.find('*/') == -1: # start of multi-line comment
in_comment = True
elif not re.match(r'\s*(#.*|//.*)?$', line, re.M):
break
sys.stdout.write(line)
# write out the prototypes
for p in prototypes:
sys.stdout.write(p + ';\n')
# continue writing out the rest of the main file
sys.stdout.write(line)
for line in f:
sys.stdout.write(line)
f.close()
# write out the contents of each of the non-main files
for path in paths[1:]:
with open(path) as g:
sys.stdout.write(g.read())
def assemble_directory(directory):
"""Assemble multiple files together in a single directory. The assembled
file is written to sys.stdout."""
# find all *.ino and *.pde files
paths = glob.glob(directory + '/*.ino')
paths += glob.glob(directory + '/*.pde')
# if there's a file whose name matches the name of the directory then
# assume that this the main file, otherwise assume main.cpp
main = directory + '/main.cpp'
for path in paths:
if os.path.splitext(os.path.basename(path))[0] == os.path.basename(directory):
main = path
break
if main in paths:
paths.remove(main)
return assemble_paths([main] + paths)
if __name__ == '__main__':
assemble_directory(sys.argv[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment