Source code for excentury.lang.mathematica.cpp_writer

"""CPP WRITER for MATHEMATICA

Helper module for writing cpp for communications with mathematica.

"""

import os
from excentury.command import error, trace, exec_cmd, date
from excentury.lang import format_input, format_return, gen_cmd
from excentury.lang import write_file


[docs]def m_name(name): """Fix names since matlab does not allow _ in names. """ word = name.split('_') last = [w[0:1].upper() + w[1:] for w in word[1:]] return '%s%s' % (word[0], ''.join(last))
def _format_param(par, in_map, test): """Helper fuction for _inputs. """ condition = '' if test: condition = '_' if in_map[par['type']][0] in ['c', 'B', 'I', 'N', 'R']: condition = '_?NumberQ' return '%s%s' % (m_name(par['name'][1:-1]), condition) def _inputs(param, in_map, test=False): """Return a string with all the inputs property formatted. """ inputs = [_format_param(par, in_map, test) for par in param] return ', '.join(inputs) TM_FUNC = r""":Begin: :Function: {name} :Pattern: {name}[{args}] :Arguments: {{{inputs}}} :ArgumentTypes: {{Manual}} :ReturnType: Manual :End: """
[docs]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')
FUNC = r"""{funcpre}void {name}() {{ /*{doc}*/ excentury::MLInterface<excentury::load_mode> XC_LI_; {input} XC_LI_.close(); {body} excentury::MLInterface<excentury::dump_mode> XC_DI_; {output} XC_DI_.close(); }}{funcepi} """
[docs]def fmt_func(func): """Given a Function object from .xcpp it will create the a valid string with the function. """ fepi = func.epilog if fepi != '': fepi = '\n' + fepi content = FUNC.format(name=m_name(func.name), body=func.body, doc=func.doc, input=format_input(func.param), output=format_return(func.ret), funcpre=func.preamble, funcepi=fepi) return content
[docs]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 _get_exec_name(cfg): """Helper function to process_function. """ fname = cfg['xcpp']['filename'] root = cfg['xcpp']['root'] mmadir = cfg['mathematica']['mma'] appdir = cfg['mathematica']['app'] base = '%s/%s/%s' % (root, mmadir, appdir) out_fname = '%s/Bin' % base if not os.path.exists(out_fname): os.mkdir(out_fname) return out_fname + "/%s.so" % fname FILE = r"""// File generated on {date} by xcpp. /*{doc}*/ #define XC_MATHEMATICA #include "mathlink.h" {pre_xc} #include <excentury/excentury.h> {preamble}{functions} int main(int argc, char* argv[]) {{ return MLMain(argc, argv); }}{epilog} """ 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 _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')
[docs]def write_cpp_file(xcf, cfg, in_map): """Writes the cpp file and compiles it. """ write_tm_file(xcf.function, cfg, in_map) fncs = [fmt_func(func) for func in xcf.function] epi = xcf.epilog if epi != '': epi = '\n' + epi content = FILE.format(date=date(), preamble=xcf.preamble, doc=xcf.docstring, pre_xc=xcf.pre_xc, functions='\n'.join(fncs), epilog=epi) in_fname = write_cpp_code(content, cfg) out_fname = _get_exec_name(cfg) fname = cfg['xcpp']['filename'] mma = cfg['mathematica']['mlink'] # COMPILING CODE _compile(fname, mma, in_fname, cfg) # LINKING _link(fname, mma, out_fname, cfg)