GiNaC  1.6.2
excompiler.cpp
Go to the documentation of this file.
00001 
00008 /*
00009  *  GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany
00010  *
00011  *  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public License
00022  *  along with this program; if not, write to the Free Software
00023  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00024  */
00025 
00026 #include "excompiler.h"
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include "config.h"
00030 #endif
00031 
00032 #include "ex.h"
00033 #include "lst.h"
00034 #include "operators.h"
00035 #include "relational.h"
00036 #include "symbol.h"
00037 
00038 #ifdef HAVE_LIBDL
00039 #include <dlfcn.h>
00040 #endif // def HAVE_LIBDL
00041 #include <fstream>
00042 #include <ios>
00043 #include <sstream>
00044 #include <stdexcept>
00045 #include <string>
00046 #include <vector>
00047 
00048 namespace GiNaC {
00049 
00050 #ifdef HAVE_LIBDL
00051     
00061 class excompiler
00062 {
00066     struct filedesc
00067     {
00068         void* module;
00069         std::string name; 
00070         bool clean_up; 
00071     };
00072     std::vector<filedesc> filelist; 
00073 public:
00077     ~excompiler()
00078     {
00079         for (std::vector<filedesc>::const_iterator it = filelist.begin(); it != filelist.end(); ++it) {
00080             clean_up(it);
00081         }
00082     }
00086     void add_opened_module(void* module, const std::string& name, bool clean_up)
00087     {
00088         filedesc fd;
00089         fd.module = module;
00090         fd.name = name;
00091         fd.clean_up = clean_up;
00092         filelist.push_back(fd);
00093     }
00097     void clean_up(const std::vector<filedesc>::const_iterator it)
00098     {
00099         dlclose(it->module);
00100         if (it->clean_up) {
00101             remove(it->name.c_str());
00102         }
00103     }
00108     void create_src_file(std::string& filename, std::ofstream& ofs)
00109     {
00110         if (filename.empty()) {
00111             // fill filename with unique random word
00112             const char* filename_pattern = "./GiNaCXXXXXX";
00113             char* new_filename = new char[strlen(filename_pattern)+1];
00114             strcpy(new_filename, filename_pattern);
00115             if (!mktemp(new_filename)) {
00116                 delete[] new_filename;
00117                 throw std::runtime_error("mktemp failed");
00118             }
00119             filename = std::string(new_filename);
00120             ofs.open(new_filename, std::ios::out);
00121             delete[] new_filename;
00122         } else {
00123             // use parameter as filename
00124             ofs.open(filename.c_str(), std::ios::out);
00125         }
00126         
00127         if (!ofs) {
00128             throw std::runtime_error("could not create source code file for compilation");
00129         }
00130 
00131         ofs << "#include <stddef.h> " << std::endl;
00132         ofs << "#include <stdlib.h> " << std::endl;
00133         ofs << "#include <math.h> " << std::endl;
00134         ofs << std::endl;
00135     }
00141     void compile_src_file(const std::string filename, bool clean_up)
00142     {
00143         std::string strcompile = "ginac-excompiler " + filename;
00144         if (system(strcompile.c_str())) {
00145             throw std::runtime_error("excompiler::compile_src_file: error compiling source file!");
00146         }
00147         if (clean_up) {
00148             remove(filename.c_str());
00149         }
00150     }
00154     void* link_so_file(const std::string filename, bool clean_up)
00155     {
00156         void* module = NULL;
00157         module = dlopen(filename.c_str(), RTLD_NOW);
00158         if (module == NULL) {
00159             throw std::runtime_error("excompiler::link_so_file: could not open compiled module!");
00160         }
00161 
00162         add_opened_module(module, filename, clean_up);
00163 
00164         return dlsym(module, "compiled_ex");
00165     }
00170     void unlink(const std::string filename)
00171     {
00172         for (std::vector<filedesc>::iterator it = filelist.begin(); it != filelist.end();) {
00173             if (it->name == filename) {
00174                 clean_up(it);
00175                 it = filelist.erase(it);
00176             } else {
00177                 ++it;
00178             }
00179         }
00180     }
00181 };
00182 
00193 static excompiler global_excompiler;
00194 
00195 void compile_ex(const ex& expr, const symbol& sym, FUNCP_1P& fp, const std::string filename)
00196 {
00197     symbol x("x");
00198     ex expr_with_x = expr.subs(lst(sym==x));
00199 
00200     std::ofstream ofs;
00201     std::string unique_filename = filename;
00202     global_excompiler.create_src_file(unique_filename, ofs);
00203 
00204     ofs << "double compiled_ex(double x)" << std::endl;
00205     ofs << "{" << std::endl;
00206     ofs << "double res = ";
00207     expr_with_x.print(GiNaC::print_csrc_double(ofs));
00208     ofs << ";" << std::endl;
00209     ofs << "return(res); " << std::endl;
00210     ofs << "}" << std::endl;
00211 
00212     ofs.close();
00213 
00214     global_excompiler.compile_src_file(unique_filename, filename.empty());
00215     // This is not standard compliant! ... no conversion between
00216     // pointer-to-functions and pointer-to-objects ...
00217     fp = (FUNCP_1P) global_excompiler.link_so_file(unique_filename+".so", filename.empty());
00218 }
00219 
00220 void compile_ex(const ex& expr, const symbol& sym1, const symbol& sym2, FUNCP_2P& fp, const std::string filename)
00221 {
00222     symbol x("x"), y("y");
00223     ex expr_with_xy = expr.subs(lst(sym1==x, sym2==y));
00224 
00225     std::ofstream ofs;
00226     std::string unique_filename = filename;
00227     global_excompiler.create_src_file(unique_filename, ofs);
00228 
00229     ofs << "double compiled_ex(double x, double y)" << std::endl;
00230     ofs << "{" << std::endl;
00231     ofs << "double res = ";
00232     expr_with_xy.print(GiNaC::print_csrc_double(ofs));
00233     ofs << ";" << std::endl;
00234     ofs << "return(res); " << std::endl;
00235     ofs << "}" << std::endl;
00236 
00237     ofs.close();
00238 
00239     global_excompiler.compile_src_file(unique_filename, filename.empty());
00240     // This is not standard compliant! ... no conversion between
00241     // pointer-to-functions and pointer-to-objects ...
00242     fp = (FUNCP_2P) global_excompiler.link_so_file(unique_filename+".so", filename.empty());
00243 }
00244 
00245 void compile_ex(const lst& exprs, const lst& syms, FUNCP_CUBA& fp, const std::string filename)
00246 {
00247     lst replacements;
00248     for (std::size_t count=0; count<syms.nops(); ++count) {
00249         std::ostringstream s;
00250         s << "a[" << count << "]";
00251         replacements.append(syms.op(count) == symbol(s.str()));
00252     }
00253 
00254     std::vector<ex> expr_with_cname;
00255     for (std::size_t count=0; count<exprs.nops(); ++count) {
00256         expr_with_cname.push_back(exprs.op(count).subs(replacements));
00257     }
00258 
00259     std::ofstream ofs;
00260     std::string unique_filename = filename;
00261     global_excompiler.create_src_file(unique_filename, ofs);
00262 
00263     ofs << "void compiled_ex(const int* an, const double a[], const int* fn, double f[])" << std::endl;
00264     ofs << "{" << std::endl;
00265     for (std::size_t count=0; count<exprs.nops(); ++count) {
00266         ofs << "f[" << count << "] = ";
00267         expr_with_cname[count].print(GiNaC::print_csrc_double(ofs));
00268         ofs << ";" << std::endl;
00269     }
00270     ofs << "}" << std::endl;
00271 
00272     ofs.close();
00273 
00274     global_excompiler.compile_src_file(unique_filename, filename.empty());
00275     // This is not standard compliant! ... no conversion between
00276     // pointer-to-functions and pointer-to-objects ...
00277     fp = (FUNCP_CUBA) global_excompiler.link_so_file(unique_filename+".so", filename.empty());
00278 }
00279 
00280 void link_ex(const std::string filename, FUNCP_1P& fp)
00281 {
00282     // This is not standard compliant! ... no conversion between
00283     // pointer-to-functions and pointer-to-objects ...
00284     fp = (FUNCP_1P) global_excompiler.link_so_file(filename, false);
00285 }
00286 
00287 void link_ex(const std::string filename, FUNCP_2P& fp)
00288 {
00289     // This is not standard compliant! ... no conversion between
00290     // pointer-to-functions and pointer-to-objects ...
00291     fp = (FUNCP_2P) global_excompiler.link_so_file(filename, false);
00292 }
00293 
00294 void link_ex(const std::string filename, FUNCP_CUBA& fp)
00295 {
00296     // This is not standard compliant! ... no conversion between
00297     // pointer-to-functions and pointer-to-objects ...
00298     fp = (FUNCP_CUBA) global_excompiler.link_so_file(filename, false);
00299 }
00300 
00301 void unlink_ex(const std::string filename)
00302 {
00303     global_excompiler.unlink(filename);
00304 }
00305 
00306 #else // def HAVE_LIBDL
00307 
00308 /*
00309  * In case no working libdl has been found by configure, the following function
00310  * stubs preserve the interface. Every function just raises an exception.
00311  */
00312 
00313 void compile_ex(const ex& expr, const symbol& sym, FUNCP_1P& fp, const std::string filename)
00314 {
00315     throw std::runtime_error("compile_ex has been disabled because of missing libdl!");
00316 }
00317 
00318 void compile_ex(const ex& expr, const symbol& sym1, const symbol& sym2, FUNCP_2P& fp, const std::string filename)
00319 {
00320     throw std::runtime_error("compile_ex has been disabled because of missing libdl!");
00321 }
00322 
00323 void compile_ex(const lst& exprs, const lst& syms, FUNCP_CUBA& fp, const std::string filename)
00324 {
00325     throw std::runtime_error("compile_ex has been disabled because of missing libdl!");
00326 }
00327 
00328 void link_ex(const std::string filename, FUNCP_1P& fp)
00329 {
00330     throw std::runtime_error("link_ex has been disabled because of missing libdl!");
00331 }
00332 
00333 void link_ex(const std::string filename, FUNCP_2P& fp)
00334 {
00335     throw std::runtime_error("link_ex has been disabled because of missing libdl!");
00336 }
00337 
00338 void link_ex(const std::string filename, FUNCP_CUBA& fp)
00339 {
00340     throw std::runtime_error("link_ex has been disabled because of missing libdl!");
00341 }
00342 
00343 void unlink_ex(const std::string filename)
00344 {
00345     throw std::runtime_error("unlink_ex has been disabled because of missing libdl!");
00346 }
00347 
00348 #endif // def HAVE_LIBDL
00349 
00350 } // namespace GiNaC

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.