-
Nicola Vigano authored
Signed-off-by:
Nicola Vigano <nicola.vigano@esrf.fr>
Nicola Vigano authoredSigned-off-by:
Nicola Vigano <nicola.vigano@esrf.fr>
dct_compile_mex_functions.py 9.63 KiB
#!/usr/bin/python
import fnmatch
import os
import sys
import subprocess
import string
import re
from dct_io_xml import DCTConf, DCTOutput
import dct_utils_platform
class MexBuilder(object):
file_extensions = [ '*.c', '*.cxx', '*.cpp' ]
@staticmethod
def getInstanceFromArgs(args, dct_dir = ""):
if dct_dir is "":
dct_dir = os.path.abspath(os.path.dirname(args[0]))
dct_dir = os.path.join(dct_dir, os.path.pardir)
dct_dir = os.path.abspath(dct_dir)
confPath = os.path.join(dct_dir, "conf.xml")
confPath = os.path.abspath(confPath)
args = args[1:]
matlab_path = ""
skip_next = False
force_compile = False
fresh_mexopts = False
verbose = 1
mfiles_to_consider = [ ]
unclassified_args = [ ]
debug = False
for index in range(len(args)):
if skip_next is False:
if args[index] == "-force-compile":
force_compile = True
elif args[index] == "-fresh-mexopts":
fresh_mexopts = True
elif args[index] in ("--verbose", "-v"):
verbose = 2
elif args[index] == "--debug":
debug = True
elif args[index] == "-c":
skip_next = True
if len(sys.argv) > (index+1):
mfiles_to_consider.append(args[index+1])
else:
raise ValueError("Not enough arguments to '-c' option")
elif args[index] == "-mp":
skip_next = True
if len(args) > (index-1):
matlab_path = args[index+1]
else:
raise ValueError("Not enough arguments for '-mp' option")
elif args[index] in ("--help", "-h"):
raise ValueError("")
else:
unclassified_args.append(args[index])
print(args[index])
else:
skip_next = False
return MexBuilder(matlab_path = matlab_path, dct_dir = dct_dir, \
extraArgs = unclassified_args, \
force_compile = force_compile, verbose = verbose, \
mfiles_to_consider = mfiles_to_consider, \
fresh_mexopts = fresh_mexopts, debug = debug)
def __init__(self, matlab_path = "", dct_dir = None, outdir = None, \
extraArgs = [], force_compile = False, verbose = 1, \
mfiles_to_consider = [], fresh_mexopts = False, debug = False):
"""
- force_compile: if true, compiles even if the file is recent
- verbose: generates a lot of output
- mfiles_to_consider: list mex files to compile (if empty, will compile all)
"""
if dct_dir is None:
dct_dir = os.getcwd()
if outdir is None:
outdir = os.path.join(dct_dir, 'bin', 'mex')
self.dct_dir = dct_dir
self.outdir = outdir
self.c_files = { }
self.mfiles_to_consider = mfiles_to_consider
self.force_compile = force_compile
self.fresh_mexopts = fresh_mexopts
self.debug = debug
self.out = DCTOutput(verboseLevel = verbose)
confPath = os.path.join(dct_dir, "conf.xml")
confPath = os.path.abspath(confPath)
self.conf = DCTConf(confPath)
if matlab_path == "":
matlab_path = self.conf.getMatlabPath()
self.matlab_dir = matlab_path
try:
self.mex_info = self.conf.getMexFiles()
except:
DCTOutput.printWarning("Couldn't get mex files info. Using plain config.")
self.mex_info = None
def printHelp(self):
launchname = os.path.basename(__file__)
print("\"%s\" builds your mex files in the DCT dir: \"%s\"" %
(launchname, self.dct_dir) )
print(" Options:")
print(" -h | --help : to show this help")
print(" -v | --verbose : to show more detailed output")
print(" --debug : to compile with debug symbols and no optimization")
print(" -c <filename> : to compile only a specific file (wildcards also apply)")
print(" -mp <matlab_dir> : to specify matlab's directory")
print(" -force-compile : to force the compilation even if not needed")
print(" -fresh-mexopts : to force the resetting of mexopts file")
def findMexs(self):
"""
def findMexs():
Finds the mex files (well, the C sources) and saves the files into the object
"""
self.out.printSubJob("Finding mex files, from: '%s'" % self.dct_dir)
for root, dir_name, file_names in os.walk(self.dct_dir):
for file_extension in self.file_extensions:
for file_name in file_names:
if fnmatch.fnmatch(file_name, file_extension):
filepath = os.path.join(root, file_name)
self.c_files[file_name] = filepath
self.out.printSubJob("These files were found:")
for file_name in self.c_files:
self.out.printSubSubJob('File', file_name + ' ( ' + self.c_files[file_name] + ' )')
print('')
def _buildMakeCmd(self, cmd, includes, lib_paths, libs, defines):
if self.out.verboseLevel > 1:
cmd.append('-v')
if self.debug is True:
cmd.append('-g')
cmd.append("-DDEBUG")
for include in includes:
cmd.append("-I" + include)
for lib_path in lib_paths:
cmd.append("-L" + lib_path)
for lib in libs:
cmd.append("-l" + lib)
for define in defines:
cmd.append("-D" + define)
self.out.printSubSubJob('File', cmd[1] + ' (cmd: ' + string.join(cmd, ' ') + ' )')
return subprocess.call(cmd)
def _compileFile(self, file_path):
"""
[Internal] def _compileFile(file_path):
Tries to compile the given file_path.
"""
compiler_path = os.path.join(self.matlab_dir, "bin", "mex")
cmd = [ compiler_path, file_path, '-outdir', self.outdir ]
includes = [ os.path.join(self.dct_dir, 'zUtil_Cxx', 'include') ]
lib_paths = []
libs = []
defines = []
if (self.mex_info is not None) \
and (self.mex_info.isExcluded(file_path) is False):
props = self.mex_info.getFileProperties(file_path)
if props is not None:
# No info at all into the xml file
includes = includes + props.get("includes")
lib_paths = lib_paths + props.get("lib_paths")
libs = libs + props.get("libs")
defines = defines + props.get("defines")
return self._buildMakeCmd(cmd, includes, lib_paths, libs, defines)
def compileFuncs(self):
"""
def compileFuncs():
Compiles the mex files into the list.
"""
if self.fresh_mexopts is True:
self.out.printSubJob("Resetting mexopts file")
dct_utils = dct_utils_platform.UtilsFactory.getMachineDep()
dct_utils.resetMatlabMexopts(self.conf.getMatlabVersion(), \
self.conf.getMatlabPath() )
listOfErrors = [];
if not os.path.exists(self.outdir):
self.out.printSubJob("Creating mex directory")
os.makedirs(self.outdir)
self.out.printSubJob("Compiling mex files:")
if (len(self.mfiles_to_consider) is 0) \
or ( (len(self.mfiles_to_consider) is 1) \
and (self.mfiles_to_consider[0] == 'all') ):
# No preferences, so let's compile everything
files_to_compile = self.c_files
else:
# Specific files
files_to_compile = self.mfiles_to_consider
# Now let's compile
for file_name in files_to_compile:
# Check if it is an actual file or a regular expression
if file_name in self.c_files:
match_list = [ file_name ]
else:
match_list = []
for cfile in self.c_files:
if re.search(file_name, cfile) is not None:
match_list.append(cfile)
if len(match_list) is 0:
errorMsg = "No file corresponds to: %s" % file_name
DCTOutput.printError(errorMsg)
listOfErrors.append(errorMsg);
# Let's compile each match
for cfile in match_list:
file_path = self.c_files[cfile]
if (self.mex_info is None) \
or ( (self.mex_info is not None) \
and (self.mex_info.isExcluded(file_path) is False) ):
ret_val = self._compileFile(file_path)
if ret_val is not 0:
listOfErrors.append("Error compiling MEX: %s (Return Value: %d)" % (file_name, ret_val))
print('')
if len(listOfErrors) is not 0:
print("Errors happened during compilation:")
for errorMsg in listOfErrors:
DCTOutput.printError('- %s' % errorMsg)
if __name__=="__main__":
try:
mex_builder = MexBuilder.getInstanceFromArgs(sys.argv)
mex_builder.findMexs()
mex_builder.compileFuncs()
except ValueError as ex:
if (len(ex.args) is not 0) and (ex.args[0] is not ""):
DCTOutput.printError(ex.args)
MexBuilder("").printHelp();
except BaseException as ex:
DCTOutput.printError(ex.args)
exit(1);