Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:01:19

0001 #include "CommonTools/Utils/interface/ExpressionEvaluator.h"
0002 #include "FWCore/Utilities/interface/GetEnvironmentVariable.h"
0003 #include "FWCore/Utilities/interface/Exception.h"
0004 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0005 
0006 #include "popenCPP.h"
0007 
0008 #include <fstream>
0009 #include <regex>
0010 #include <dlfcn.h>
0011 
0012 // #define VI_DEBUG
0013 
0014 #ifdef VI_DEBUG
0015 #include <iostream>
0016 #define COUT std::cout
0017 #else
0018 #define COUT LogDebug("ExpressionEvaluator")
0019 #endif
0020 
0021 using namespace reco::exprEvalDetails;
0022 
0023 namespace {
0024   std::string generateName() {
0025     auto n1 = execSysCommand("uuidgen | sed 's/-//g'");
0026     n1.pop_back();
0027     return n1;
0028   }
0029 
0030   void remove(std::string const& name, std::string const& tmpDir = "/tmp") {
0031     std::string sfile = tmpDir + "/" + name + ".cc";
0032     std::string ofile = tmpDir + "/" + name + ".so";
0033 
0034     std::string rm = "rm -f ";
0035     rm += sfile + ' ' + ofile;
0036 
0037     system(rm.c_str());
0038   }
0039 
0040 }  // namespace
0041 
0042 namespace reco {
0043 
0044   ExpressionEvaluator::ExpressionEvaluator(const char* pkg, const char* iname, std::string const& iexpr)
0045       : m_name("VI_" + generateName()) {
0046     std::string pch = pkg;
0047     pch += "/src/precompile.h";
0048     std::string quote("\"");
0049 
0050     auto arch = edm::getEnvironmentVariable("SCRAM_ARCH");
0051     auto baseDir = edm::getEnvironmentVariable("CMSSW_BASE");
0052     auto relDir = edm::getEnvironmentVariable("CMSSW_RELEASE_BASE");
0053 
0054     std::string sfile = baseDir + "/tmp/" + m_name + ".cc";
0055     std::string ofile = baseDir + "/tmp/" + m_name + ".so";
0056 
0057     std::string incDir = "/include/" + arch + "/";
0058     std::string cxxf;
0059     {
0060       // look in local dir
0061       std::string file = baseDir + incDir + pch + ".cxxflags";
0062       std::ifstream ss(file.c_str());
0063       COUT << "local file: " << file << std::endl;
0064       if (ss) {
0065         std::getline(ss, cxxf);
0066         incDir = baseDir + incDir;
0067       } else {
0068         // look in release area
0069         std::string file = relDir + incDir + pch + ".cxxflags";
0070         COUT << "file in release area: " << file << std::endl;
0071         std::ifstream ss(file.c_str());
0072         if (ss) {
0073           std::getline(ss, cxxf);
0074           incDir = relDir + incDir;
0075         } else {
0076           // look in release is a patch area
0077           auto paDir = edm::getEnvironmentVariable("CMSSW_FULL_RELEASE_BASE");
0078           if (paDir.empty())
0079             throw cms::Exception("ExpressionEvaluator", "error in opening patch area for " + baseDir);
0080           std::string file = paDir + incDir + pch + ".cxxflags";
0081           COUT << "file in base release area: " << file << std::endl;
0082           std::ifstream ss(file.c_str());
0083           if (!ss)
0084             throw cms::Exception(
0085                 "ExpressionEvaluator",
0086                 pch + " file not found neither in " + baseDir + " nor in " + relDir + " nor in " + paDir);
0087           std::getline(ss, cxxf);
0088           incDir = paDir + incDir;
0089         }
0090       }
0091 
0092       {
0093         std::regex rq("-I[^ ]+");
0094         cxxf = std::regex_replace(cxxf, rq, std::string(""));
0095       }
0096       {
0097         std::regex rq("=\"");
0098         cxxf = std::regex_replace(cxxf, rq, std::string("='\""));
0099       }
0100       {
0101         std::regex rq("\" ");
0102         cxxf = std::regex_replace(cxxf, rq, std::string("\"' "));
0103       }
0104       COUT << '|' << cxxf << "|\n" << std::endl;
0105     }
0106 
0107     std::string cpp = "c++ -H -Wall -shared -Winvalid-pch ";
0108     cpp += cxxf;
0109     cpp += " -I" + incDir;
0110     cpp += " -o " + ofile + ' ' + sfile + " 2>&1\n";
0111 
0112     COUT << cpp << std::endl;
0113 
0114     //  prepare the file to compile
0115     std::string factory = "factory" + m_name;
0116 
0117     std::string source = std::string("#include ") + quote + pch + quote + "\n";
0118     source += "struct " + m_name + " final : public " + iname + "{\n";
0119     source += iexpr;
0120     source += "\n};\n";
0121 
0122     source += "extern " + quote + 'C' + quote + ' ' + std::string(iname) + "* " + factory + "() {\n";
0123     source += "static " + m_name + " local;\n";
0124     source += "return &local;\n}\n";
0125 
0126     COUT << source << std::endl;
0127 
0128     {
0129       std::ofstream tmp(sfile.c_str());
0130       tmp << source << std::endl;
0131     }
0132 
0133     // compile
0134     auto ss = execSysCommand(cpp);
0135     COUT << ss << std::endl;
0136 
0137     void* dl = dlopen(ofile.c_str(), RTLD_LAZY);
0138     if (!dl) {
0139       remove(m_name, baseDir + "/tmp");
0140       throw cms::Exception("ExpressionEvaluator",
0141                            std::string("compilation/linking failed\n") + cpp + ss + "dlerror " + dlerror());
0142       return;
0143     }
0144 
0145     m_expr = dlsym(dl, factory.c_str());
0146     remove(m_name, baseDir + "/tmp");
0147   }
0148 
0149   ExpressionEvaluator::~ExpressionEvaluator() { remove(m_name, edm::getEnvironmentVariable("CMSSW_BASE") + "/tmp"); }
0150 
0151 }  // namespace reco