Attached it a python script I wrote to construct dependencies for
LilyPond. It works like makedepend and has similar command line
options.
One thing to note is that this script searches for included files in
the same directory as the _current_ file being processed instead of
only in the directory of the root file sent to lilypond. I hope that
issue 391 (http://code.google.com/p/lilypond/issues/detail?id=391&q=include)
is resolved in favor of mimicing the C preprocessor.
An interesting feature to get around make's inability to handle spaces
in path names is to, optionally, create symbolic links for each file
that has spaces in its path name.
enjoy!
-cj
#!/usr/local/bin/python
# written by CJ Bell
"""Create dependencies in makefiles for LilyPond scripts
Usage: makedepend_ly [options] files...
Options:
-h / --help
Print this message and exit.
-f, --file=MAKEFILE
Filename. This allows you to specify an alternate makefile in which
makedepend_ly can place its output. Specifying ``-'' as the file name
(i.e., -f-) sends the output to standard output instead of modifying
an existing file.
-I, --include=INCLUDEDIR
Include directory. This option tells makedepend_ly to prepend
INCLUDEDIR to its list of directories to search when it encounters an
\include directive. By default, makedepend_ly only searches the
standard include directories.
-Y, --onlyinclude=INCLUDEDIR
Replace all of the standard include directories with the single
specified include directory.
-a, --append
Append the dependencies to the end of the file instead of replacing
them.
-s, --start=STRING
Starting string delimiter. This option permits you to specify a
different string for makedepend_ly to look for in the makefile.
"""
import tempfile
import os
import shutil
import sys
import getopt
import fileinput
import re
# Pattern used to parse for a lilypond include
inclfn = re.compile(r"[ \t]*\\include[
\t]+\"(?P<filename>(?:(?:\\[\"])|[^\"])*)\"")
ntPath = 'C:/Program Files/LilyPond/usr/share/lilypond/current/ly'
posixPath = '/usr/share/lilypond/current/ly'
includePaths = []
standardIncludes = []
if os.path.exists(ntPath):
standardIncludes.append(ntPath)
if os.path.exists(posixPath):
standardIncludes.append(posixPath)
if 'relpath' not in dir(os.path):
os.path.relpath = lambda p: p
##############################################################################
def main(argv):
global includePaths
linkspaces = False
append = False
starting_str = '# DO NOT DELETE THIS LINE -- makedepend_ly depends on it.'
if os.path.exists('makefile'):
outputFile = 'makefile'
else:
outputFile = 'Makefile'
try:
longopts =
['help','file=','include=','onlyinclude=','linkspaces=','append','start=']
opts, files = getopt.getopt(argv, 'hf:I:Y:as:', longopts)
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit()
if opt in ('-f','--file'):
outputFile = arg
if opt in ('-I','--include'):
if not os.path.exists(arg):
print "Included directory " + arg + " doesn't exist"
sys.exit(1)
includePaths.append(arg)
if opt in ('-Y','--onlyinclude'):
if not os.path.exists(arg):
print "Included directory " + arg + " doesn't exist"
sys.exit(1)
standardInclude = [arg]
if opt == '--linkspaces':
linkspaces = True
ns_link_dir = arg
if opt in ('-a','--append'):
append = True
if opt in ('-s','--start'):
starting_string = arg
includePaths+= standardIncludes
toCheck = set()
for file in files:
toCheck.add(os.path.join(os.path.abspath(file)))
# Prevents cycles
checked = set()
# current directory
cd = './'
depends = dict()
while toCheck:
files = toCheck - checked
toCheck = set()
for file in files:
included = parseFile(file, includePaths)
depends[file] = included
toCheck |= included
checked.add(file)
# Make links for each filename with a space so it can be referred-to in the
# makefile
if linkspaces:
try:
os.mkdir(ns_link_dir)
except EnvironmentError, err:
print err
new_keys = []
for file in depends.keys():
new_keys.append(linkNoSpace(file, ns_link_dir))
new_values = [];
for deps in depends.values():
new_deps = []
for file in deps:
new_deps.append(linkNoSpace(file, ns_link_dir))
new_values.append(new_deps)
depends = dict(zip(new_keys, new_values))
# Output dependencies
old_f = None
if outputFile == '-':
f = sys.stdout
else:
try:
old_f = open(outputFile, 'r')
except IOError, err:
if err.errno != 2:
pass
f = open(outputFile, 'w')
f.write(starting_str + '\n')
else:
# Copy the file up until the starting deliminator
f = tempfile.TemporaryFile()
startFound = False
for line in old_f:
f.write(line)
if line == starting_str+'\n':
startFound = True
break
if not startFound:
f.write('\n' + starting_str + '\n')
if not f:
print "Cannot open " + outputFile + " for writing"
sys.exit()
for file, deps in depends.items():
f.write(os.path.relpath(file) + ': ' + reduce(lambda a, b: a+'
'+os.path.relpath(b), deps, "")+'\n\n')
if old_f:
old_f.close()
old_f = open(outputFile, 'w')
f.seek(0)
shutil.copyfileobj(f,old_f)
old_f.close()
if f != sys.stdout:
f.close()
# End main
##############################################################################
##############################################################################
def usage():
print __doc__
# End usage
##############################################################################
##############################################################################
def linkNoSpace(file, basedir):
if ' ' not in file:
return file
new_filename = os.path.basename(file)
if os.path.exists(os.path.join(basedir,new_filename)):
if os.readlink(os.path.join(basedir,new_filename)) == file:
return os.path.join(basedir,new_filename)
n = 2
while os.path.exists(os.path.join(basedir,str(n) + '.' + new_filename)):
n+= 1
new_filename = str(n) + '.' + new_filename
os.symlink(file, os.path.join(basedir,new_filename))
return os.path.join(basedir,new_filename)
# End linkNoSpace
##############################################################################
##############################################################################
def parseFile(file, includePaths):
includes = set()
cd = os.path.dirname(file)
for line in fileinput.input(file):
try:
f = parseLine(line, cd, includePaths)
except EnvironmentError, err:
print "In " + os.path.relpath(file) + ", " + err.strerror + ": " +
err.filename
else:
if f is not None:
includes.add(f)
return includes
# End parseFile
##############################################################################
##############################################################################
def parseLine(line, cd, includePaths):
global inclfn
match = inclfn.match(line)
if match is None:
return None
file = match.group('filename')
# cheack each include path, then the file's directory
for incl in includePaths+[cd]:
f = os.path.join(incl,file)
if os.path.exists(os.path.join(incl,file)):
return f
# included file can't be found
raise EnvironmentError(-1,"cannot find included file", file)
# End parseLine
##############################################################################
if __name__ == "__main__":
main(sys.argv[1:])
_______________________________________________
lilypond-user mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/lilypond-user