1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
#include "CommonTools/Utils/interface/ExpressionEvaluator.h"
#include "FWCore/Utilities/interface/GetEnvironmentVariable.h"
#include "FWCore/Utilities/interface/Exception.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "popenCPP.h"
#include <fstream>
#include <regex>
#include <dlfcn.h>
// #define VI_DEBUG
#ifdef VI_DEBUG
#include <iostream>
#define COUT std::cout
#else
#define COUT LogDebug("ExpressionEvaluator")
#endif
using namespace reco::exprEvalDetails;
namespace {
std::string generateName() {
auto n1 = execSysCommand("uuidgen | sed 's/-//g'");
n1.pop_back();
return n1;
}
void remove(std::string const& name, std::string const& tmpDir = "/tmp") {
std::string sfile = tmpDir + "/" + name + ".cc";
std::string ofile = tmpDir + "/" + name + ".so";
std::string rm = "rm -f ";
rm += sfile + ' ' + ofile;
system(rm.c_str());
}
} // namespace
namespace reco {
ExpressionEvaluator::ExpressionEvaluator(const char* pkg, const char* iname, std::string const& iexpr)
: m_name("VI_" + generateName()) {
std::string pch = pkg;
pch += "/src/precompile.h";
std::string quote("\"");
auto arch = edm::getEnvironmentVariable("SCRAM_ARCH");
auto baseDir = edm::getEnvironmentVariable("CMSSW_BASE");
auto relDir = edm::getEnvironmentVariable("CMSSW_RELEASE_BASE");
std::string sfile = baseDir + "/tmp/" + m_name + ".cc";
std::string ofile = baseDir + "/tmp/" + m_name + ".so";
std::string incDir = "/include/" + arch + "/";
std::string cxxf;
{
// look in local dir
std::string file = baseDir + incDir + pch + ".cxxflags";
std::ifstream ss(file.c_str());
COUT << "local file: " << file << std::endl;
if (ss) {
std::getline(ss, cxxf);
incDir = baseDir + incDir;
} else {
// look in release area
std::string file = relDir + incDir + pch + ".cxxflags";
COUT << "file in release area: " << file << std::endl;
std::ifstream ss(file.c_str());
if (ss) {
std::getline(ss, cxxf);
incDir = relDir + incDir;
} else {
// look in release is a patch area
auto paDir = edm::getEnvironmentVariable("CMSSW_FULL_RELEASE_BASE");
if (paDir.empty())
throw cms::Exception("ExpressionEvaluator", "error in opening patch area for " + baseDir);
std::string file = paDir + incDir + pch + ".cxxflags";
COUT << "file in base release area: " << file << std::endl;
std::ifstream ss(file.c_str());
if (!ss)
throw cms::Exception(
"ExpressionEvaluator",
pch + " file not found neither in " + baseDir + " nor in " + relDir + " nor in " + paDir);
std::getline(ss, cxxf);
incDir = paDir + incDir;
}
}
{
std::regex rq("-I[^ ]+");
cxxf = std::regex_replace(cxxf, rq, std::string(""));
}
{
std::regex rq("=\"");
cxxf = std::regex_replace(cxxf, rq, std::string("='\""));
}
{
std::regex rq("\" ");
cxxf = std::regex_replace(cxxf, rq, std::string("\"' "));
}
COUT << '|' << cxxf << "|\n" << std::endl;
}
std::string cpp = "c++ -H -Wall -shared -Winvalid-pch ";
cpp += cxxf;
cpp += " -I" + incDir;
cpp += " -o " + ofile + ' ' + sfile + " 2>&1\n";
COUT << cpp << std::endl;
// prepare the file to compile
std::string factory = "factory" + m_name;
std::string source = std::string("#include ") + quote + pch + quote + "\n";
source += "struct " + m_name + " final : public " + iname + "{\n";
source += iexpr;
source += "\n};\n";
source += "extern " + quote + 'C' + quote + ' ' + std::string(iname) + "* " + factory + "() {\n";
source += "static " + m_name + " local;\n";
source += "return &local;\n}\n";
COUT << source << std::endl;
{
std::ofstream tmp(sfile.c_str());
tmp << source << std::endl;
}
// compile
auto ss = execSysCommand(cpp);
COUT << ss << std::endl;
void* dl = dlopen(ofile.c_str(), RTLD_LAZY);
if (!dl) {
remove(m_name, baseDir + "/tmp");
throw cms::Exception("ExpressionEvaluator",
std::string("compilation/linking failed\n") + cpp + ss + "dlerror " + dlerror());
return;
}
m_expr = dlsym(dl, factory.c_str());
remove(m_name, baseDir + "/tmp");
}
ExpressionEvaluator::~ExpressionEvaluator() { remove(m_name, edm::getEnvironmentVariable("CMSSW_BASE") + "/tmp"); }
} // namespace reco
|