def _eval_condition(cond, ARG, CFG, line_num, fname): """Evaluates a string using the eval function. It prints a warning if there are any errors. Returns the result of the evaluation and an error number: 0 if everything is fine, 1 if there was an error. """ ARG.FILEPATH = '%s/%s/%s' % (ARG.cfg, CFG['xcpp']['path'], ARG.inputfile) try: # pylint: disable=eval-used # To be able to evaluate a condition without creating a whole # new parser we can use the eval function. We could have use # a python file as a configuration but then there would be # no simple structure to the files. cond = eval(cond) enum = 0 # pylint: disable=broad-except # Anything can go wrong during the execution of the `eval` # function. For this reason we must try to catch anything that # may come our way so that we may give out a warning message # and ignore it. except Exception as exception: cond = None enum = 1 trace( 'WARNING: error in line %d of %r: %s\n' % ( line_num, fname, exception.message ) ) return cond, enum
def _compile(fname, mma, in_fname, cfg): """Helper function. """ cmd = gen_cmd(cfg, 'mathematica', int(cfg['mathematica']['debug'])) cmd = '%s%s -c -I%s -o %s.o' % (cmd, in_fname, mma, fname) trace(' - compiling %s ... ' % in_fname) _, err, _ = exec_cmd(cmd) if err != '': msg = "\nERROR: The command\n%s\n\nreturned the following " \ "error:\n%s" % (str(cmd), str(err)) error(msg) trace('done\n')
def write_file(in_fname, contents): """Helper function to write contents to in_fname. """ make_new = True if os.path.exists(in_fname): tmp = open(in_fname, 'r').read() if tmp[tmp.find('\n'):] == contents[contents.find('\n'):]: make_new = False if make_new: with open(in_fname, 'w') as tmp: tmp.write(contents) trace('[NEW CONTENT]\n') else: trace('[NO CHANGE]\n')
def write_matlab_file(func, cfg, in_map): """Writes the m file. """ pkg = cfg['xcpp']['filename'] content = M_FILE.format(doc=_format_help(func, pkg), pkg=pkg, name=func.name, args=_args(func.param), load=cfg['matlab']['load'], dump=cfg['matlab']['dump'], inputs=_format_input(func.param, in_map)) base = cfg['matlab']['pkg'] pkg = cfg['xcpp']['filename'] in_fname = '%s/%s.m' % (base, func.name) trace(' + inspecting +%s/%s.m ... ' % (pkg, func.name)) write_file(in_fname, content)
def _write_py_file(contents, cfg): """Helper function for process_function. """ root = cfg['xcpp']['root'] dest_dir = cfg['python']['wrapper'] if dest_dir[0] == '/': base = dest_dir else: base = '%s/%s' % (root, dest_dir) filename = cfg['xcpp']['filename'] in_fname = '%s/%s.py' % (base, filename) trace('+ inspecting %s.py ... ' % filename) write_file(in_fname, contents) return in_fname
def _write_cpp_file(contents, cfg): """Helper function. """ root = cfg['xcpp']['root'] cppdir = cfg['python']['dir'] if cppdir[0] == '/': base = cppdir else: base = '%s/%s' % (root, cppdir) filename = cfg['xcpp']['filename'] in_fname = '%s/%s_pylib.cpp' % (base, filename) trace('+ inspecting %s_pylib.cpp ... ' % filename) write_file(in_fname, contents) return in_fname
def write_cpp_code(content, cfg): """Helper function for process_function. """ root = cfg['xcpp']['root'] cppdir = cfg['mathematica']['dir'] if cppdir[0] == '/': base = cppdir else: base = '%s/%s' % (root, cppdir) filename = cfg['xcpp']['filename'] in_fname = '%s/%s_mathlink.cpp' % (base, filename) trace('+ inspecting %s_mathlink.cpp ... ' % filename) write_file(in_fname, content) return in_fname
def _write_file(contents, func, cfg): """Helper function for process_function. """ root = cfg['xcpp']['root'] cppdir = cfg['cpp']['dir'] if cppdir[0] == '/' or cppdir == '.': base = cppdir else: base = '%s/%s' % (root, cppdir) filename = cfg['xcpp']['filename'] in_fname = '%s/%s-%s.cpp' % (base, filename, func.name) msg = '[%d] inspecting %s-%s.cpp ... ' trace(msg % (func.num, filename, func.name)) write_file(in_fname, contents) return in_fname
def _compile_cpp_file(in_fname, func, cfg): """Helper function """ out_fname = '%s/%s_mex' % (cfg['matlab']['pkg'], func.name) mexbin, _, _ = exec_cmd('mexext') mexbin = '%s.%s' % (out_fname, mexbin.strip()) force = cfg['matlab']['force'] epilog = cfg['matlab']['epilog'] verbose = cfg['matlab']['verbose'] make_new = True if isinstance(force, list) and (len(force) == 0 or func.num in force): pass elif force in ['True', 'true']: pass elif os.path.exists(mexbin): date_in = datetime.fromtimestamp(os.path.getmtime(in_fname)) date_out = datetime.fromtimestamp(os.path.getmtime(mexbin)) if date_in < date_out: make_new = False trace(' - skipping compilation\n') if make_new: cmd = gen_cmd(cfg, 'matlab', int(cfg['matlab']['debug'])) cmd = '%s%s -output %s %s' % (cmd, in_fname, out_fname, epilog) trace(' - compiling %s ... ' % in_fname) if verbose is True or verbose in ['true', 'True']: cmd += ' -v' trace('\n * command:\n %s\n * ' % str(cmd)) exec_cmd(cmd, True) else: _, err, _ = exec_cmd(cmd) if err != '': msg = "\nERROR: The command\n%s\n\nreturned the following " \ "error:\n%s" % (str(cmd), str(err)) error(msg) trace('done\n')
def check_inputs(xcfile, cfg, lang): """Make an executable with all the inputs the xcpp file uses and make sure that all of them are valid. Return a dictionary with the info on all the inputs. """ fname = cfg['xcpp']['filename'] fname, fvar = gen_input_file(xcfile, fname) cmd = '%s%s ' % (gen_cmd(cfg, lang, 1), fname) trace(' - compiling %s ... ' % fname) out, err, _ = exec_cmd(cmd) if err != '': msg = "ERROR: The command\n%s\n\nreturned the following " \ "error:\n%s" % (str(cmd), str(err)) error(msg) trace('done\n') trace(' - running executable ... ') out, err, _ = exec_cmd('./a.out') if err != '': msg = "\nERROR: The command `%s` returned the following " \ "error:\n%s" % ('./a.out', str(err)) error(msg) trace('done\n') var, defs = TextParser(out).parse_info() info = _make_map(var, fvar) os.remove('a.out') os.remove(fname) return info, defs
def _link(fname, mma, out_fname, cfg): """Helper function. """ cmd = gen_cmd(cfg, 'mathematica', int(cfg['mathematica']['debug'])) files = '%s.o tmp-%s.o' % (fname, fname) extras = '-lMLi3 -lstdc++ -framework Foundation' cmd = '%s%s -I%s -L%s %s -o %s' % (cmd, files, mma, mma, extras, out_fname) trace(' - preparing library ... ') _, err, _ = exec_cmd(cmd) if err != '': msg = "\nERROR: The command\n%s\n\nreturned the following " \ "error:\n%s" % (str(cmd), str(err)) error(msg) os.remove('%s.o' % fname) os.remove('tmp-%s.o' % fname) trace('done\n')
def read_config(arg): """Read the configuration file xcpp.config""" path = arg.cfg if path == '.' and not os.path.exists('xcpp.config'): if 'XCPP_CONFIG_PATH' in os.environ: tmp_path = os.environ['XCPP_CONFIG_PATH'] if os.path.exists('%s/xcpp.config' % tmp_path): trace("Configured with: '%s/xcpp.config'\n" % tmp_path) path = tmp_path elif not os.path.exists('%s/xcpp.config' % path): error("ERROR: %s/xcpp.config does not exist\n" % path) arg.cfg = path try: config = _read_config('%s/xcpp.config' % path, arg) except IOError: config = OrderedDict() return config
def update_entries(path): """Updates the projects entries. Checks to see if the `xcpp.config` and `.xcpprc` files exists. """ data = get_entries() path = pth.abspath(path) try: config = _read_config('%s/xcpp.config' % path) except IOError: error("ERROR: `xcpp.config` not found in %r\n" % path) if not pth.exists('%s/.xcpprc' % path): error("ERROR: `xcpprc` not found in %r\n" % path) if 'xcpp' not in config: error("ERROR: Missing `xcpp` section in `xcpp.config`\n") if 'name' not in config['xcpp']: error("ERROR: Missing `xcpp.name` value in `xcpp.config`\n") if not append_entry(data, config['xcpp']['name'], path): trace("%r has been previously added\n" % path) set_entries(data)
def write_matlab_defs(cfg, defs): """Write a file containing the definition used in the package. """ contents = DEF_FILE % (cfg['xcpp']['filename'], date(), _format_defs(defs)) base = cfg['matlab']['pkg'] pkg = cfg['xcpp']['filename'] in_fname = '%s/xc_def.m' % base trace('* inspecting +%s/xc_def.m ... ' % pkg) write_file(in_fname, contents) if defs.keys(): inputs = 'The posible inputs are: \n%%\n%% %s' inputs = inputs % '\n%% '.join(defs.keys()) else: inputs = '' contents = XC_STRUCT_FILE.format(pkg=pkg, date=date(), inputs=inputs) in_fname = '%s/xc_struct.m' % base trace('* inspecting +%s/xc_struct.m ... ' % pkg) write_file(in_fname, contents)
def write_m_file(xcf, cfg): """Writes the m file. """ root = cfg['xcpp']['root'] app = cfg['mathematica']['app'] usage = '\n\n'.join([_format_help(func, cfg) for func in xcf.function]) pkgname = cfg['xcpp']['filename'] funcnames = ',\n '.join([m_name(func.name) for func in xcf.function]) errors = '\n'.join([_format_error(func, cfg) for func in xcf.function]) content = M_FILE.format(date=date(), app=app, pkgname=pkgname, error=errors, usage=usage, funcnames=funcnames) dest_dir = '%s/%s' % (cfg['mathematica']['mma'], app) if dest_dir[0] == '/': base = dest_dir else: base = '%s/%s' % (root, dest_dir) filename = cfg['xcpp']['filename'] in_fname = '%s/%s.m' % (base, filename) trace('+ inspecting %s/%s.m ... ' % (app, filename)) write_file(in_fname, content)
def gen_input_file(xcfile, filename): """Generate the input file and return the name of the file it prints along with a dictionary containing the datatypes it contains. """ funcpre = ''.join([func.preamble for func in xcfile.function]) cont = """// Temporary file generated on {date} by xcpp. {pre_xc}#include <excentury/excentury.h> {preamble}{funcpre} int main() {{ excentury::TextInterface<excentury::dump_mode> XC_DI_(stdout); %s XC_DI_.close(); }} """.format(date=date(), pre_xc=xcfile.pre_xc, preamble=xcfile.preamble, funcpre=funcpre) var = dict() num = 1 tmp1 = ' {type} {var}{ctor}; XC_DI_.dump({var}, "{var}");\n' tmp2 = ' {type} {var}{ctor}; XC_DI_.dump({var}, "{var}", {sample});\n' inputs = '' for func in xcfile.function: for par in func.param: if par['type'] not in var: vname = 'var%d_%s' % (num, par['name'][1:-1]) var[par['type']] = vname if 'sample' in par: sample = par['sample'].replace(par['name'][1:-1], vname) inputs += tmp2.format(type=par['type'], var=vname, ctor=par['ctor'], sample=sample) else: inputs += tmp1.format(type=par['type'], var=vname, ctor=par['ctor']) num += 1 fname = 'inputs-%s.cpp' % filename trace('+ writing temporary file %s ... ' % fname) with open(fname, 'w') as tmp: tmp.write(cont % inputs) trace('done\n') return fname, var
def _compile_cpp_file(in_fname, cfg): """Helper function. """ out_fname = _get_exec_name(cfg) epilog = cfg['python']['epilog'] verbose = cfg['python']['verbose'] cmd = gen_cmd(cfg, 'python', int(cfg['python']['debug'])) cmd = '%s --shared -fPIC %s -o %s %s' % (cmd, in_fname, out_fname, epilog) trace(' - compiling %s ... ' % in_fname) if verbose is True or verbose in ['true', 'True']: trace('\n * command:\n %s\n * ' % str(cmd)) _, err, _ = exec_cmd(cmd) if err != '': msg = "\nERROR: The command\n%s\n\nreturned the following " \ "error:\n%s" % (str(cmd), str(err)) error(msg) trace('done\n')
def process_function(xcf, cfg, func): """Given a Function object from .xcpp it will create the contents of a valid cpp file that can be compiled for a valid executable. """ in_fname = cfg['xcpp']['filename'] epilog = func.epilog if epilog != '': epilog += '\n' contents = TEMPLATE.format(date=date(), pre_xc=xcf.pre_xc, preamble=xcf.preamble, help=_format_help(func, in_fname), param=_format_input(func.param), doc=func.doc, body=func.body, load=cfg['cpp']['load'].capitalize(), dump=cfg['cpp']['dump'].capitalize(), input=format_input(func.param), output=format_return(func.ret), out=func.out, funcpre=func.preamble, funcepi=epilog, epilog=xcf.epilog) in_fname = _write_file(contents, func, cfg) out_fname = _get_exec_name(func, cfg) force = cfg['cpp']['force'] make_new = True if isinstance(force, list) and (len(force) == 0 or func.num in force): pass elif force in ['True', 'true']: pass elif os.path.exists(out_fname): date_in = datetime.fromtimestamp(os.path.getmtime(in_fname)) date_out = datetime.fromtimestamp(os.path.getmtime(out_fname)) if date_in < date_out: make_new = False trace(' - skipping compilation\n') if make_new: cmd = gen_cmd(cfg, 'cpp', int(cfg['cpp']['debug'])) cmd = '%s%s -o %s' % (cmd, in_fname, out_fname) trace(' - compiling %s ... ' % in_fname) _, err, _ = exec_cmd(cmd) if err != '': msg = "\nERROR: The command\n%s\n\nreturned the following " \ "error:\n%s" % (str(cmd), str(err)) error(msg) trace('done\n')
def _write_cpp_file(contents, func, cfg): """Helper function """ root = cfg['xcpp']['root'] cppdir = cfg['matlab']['dir'] if cppdir[0] == '/': base = cppdir else: base = '%s/%s' % (root, cppdir) filename = cfg['xcpp']['filename'] in_fname = '%s/%s-%s_mex.cpp' % (base, filename, func.name) msg = '[%d] inspecting %s-%s_mex.cpp ... ' trace(msg % (func.num, filename, func.name)) make_new = True if os.path.exists(in_fname): tmp = open(in_fname, 'r').read() if tmp[tmp.find('\n'):] == contents[contents.find('\n'):]: make_new = False if make_new: with open(in_fname, 'w') as tmp: tmp.write(contents) trace('[NEW CONTENT]\n') else: trace('[NO CHANGE]\n') return in_fname
def write_tm_file(funcs, cfg, in_map): """Write the tm file and compile it with mprep. """ fname = cfg['xcpp']['filename'] contents = ':Evaluate: Begin["`Private`"]\n\n' for func in funcs: contents += TM_FUNC.format(name=m_name(func.name), args=_inputs(func.param, in_map, True), inputs=_inputs(func.param, in_map)) contents += ':Evaluate: End[]\n' in_fname = 'tmp-%s.tm' % fname trace('+ writing temporary file %s ... ' % in_fname) with open(in_fname, 'w') as tmp: tmp.write(contents) trace('done\n') mma = cfg['mathematica']['mlink'] # MPREP cmd = '%s/mprep %s -o %s' % (mma, in_fname, 'tmp-%s.cpp' % fname) trace(' - preparing %s ... ' % in_fname) _, err, _ = exec_cmd(cmd) if err != '': msg = "\nERROR: The command\n%s\n\nreturned the following " \ "error:\n%s" % (str(cmd), str(err)) error(msg) trace('done\n') # COMPILE_TM cmd = gen_cmd(cfg, 'mathematica', int(cfg['mathematica']['debug'])) in_fname = 'tmp-%s.cpp' % fname out_fname = 'tmp-%s.o' % fname cmd = '%s%s -c -I%s -o %s' % (cmd, in_fname, mma, out_fname) trace(' - compiling %s ... ' % in_fname) _, err, _ = exec_cmd(cmd) if err != '': msg = "\nERROR: The command\n%s\n\nreturned the following " \ "error:\n%s" % (str(cmd), str(err)) error(msg) # CLEAN UP os.remove('tmp-%s.cpp' % fname) os.remove('tmp-%s.tm' % fname) trace('done\n')