11 #include <boost/algorithm/string/case_conv.hpp> 12 #include <boost/filesystem.hpp> 32 auto cp = getenv(
"VCSN_VERBOSE");
33 std::istringstream is{cp ? cp :
"0"};
45 :
std::runtime_error(what)
51 #define XGETENV(Name) xgetenv(#Name, Name) 56 config(
const std::string& var)
58 auto envvar =
"VCSN_" + boost::algorithm::to_upper_copy(var);
59 if (
auto cp = getenv(envvar.c_str()))
62 return get_config()[
"configuration"][var].str();
69 if (!res.empty() && res[0] ==
'~')
71 assert(res.size() == 1 || res[1] ==
'/');
73 char const *hdrive = getenv(
"HOMEDRIVE");
74 char const *hres = getenv(
"HOMERES");
76 res.replace(0, 1, home);
77 else if (hdrive && hres)
78 res.replace(0, 1, std::string(hdrive) + hres);
80 res.replace(0, 1,
xgetenv(
"VCSN_TMPDIR",
"/tmp"));
86 void ensure_parent_directory(
const std::string& path)
88 boost::filesystem::path p(path);
89 boost::filesystem::create_directories(p.parent_path());
93 std::string tmpname(std::string res)
116 void print(
const std::string& base)
118 ensure_parent_directory(base);
121 auto tmp = tmpname(base);
123 auto&& o = std::ofstream{tmp +
".cc"};
125 "cannot create ", tmp+
".cc",
": ", strerror(errno));
129 boost::filesystem::remove(tmp +
".cc");
131 boost::filesystem::rename(tmp +
".cc", base +
".cc");
142 void print_type(
const std::string&
type)
150 void throw_compiler_errors(std::string cmd,
151 const std::string& err)
170 static auto r1 = std::regex{
"static assertion failed: (.*)$",
171 std::regex::extended};
172 static auto r2 = std::regex{
"static_assert failed \"(.*)\"$",
173 std::regex::extended};
177 while (std::getline(*is, line))
178 if (std::regex_search(line, smatch, r1)
179 || std::regex_search(line, smatch, r2))
180 assertions += std::string(smatch[1]) +
'\n';
183 cmd +=
"\n compiler error messages:\n";
186 throw jit_error(assertions,
" failed command:\n " + cmd);
193 void cxx(std::string cmd,
const std::string& tmp)
195 auto err = tmp +
".err";
196 if (getenv(
"VCSN_DEBUG"))
197 std::cerr <<
"run: " << cmd <<
'\n';
198 if (system((cmd +
" 2>'" + err +
"'").c_str()))
199 throw_compiler_errors(cmd, err);
203 auto&&
log = std::ifstream{err};
205 "cannot read ", err,
": ", strerror(errno));
206 std::cerr <<
log.rdbuf();
211 boost::filesystem::remove(err);
218 void cxx_compile(
const std::string& base)
220 auto tmp = tmpname(base);
223 auto cmd = (std::string{
"LC_ALL=C"}
224 +
" " + config(
"ccache")
225 +
" " + config(
"cxx")
226 +
" " + config(
"cxxflags")
227 +
" " + config(
"cppflags")
228 +
" -fPIC '" + base +
".cc' -c" 229 +
" -o '" + tmp +
".o'");
236 void cxx_link(
const std::string& base)
238 auto tmp = tmpname(base);
239 auto cmd = (std::string{
"LC_ALL=C"}
240 +
" " + config(
"cxx")
241 +
" " + config(
"cxxflags")
242 +
" " + config(
"ldflags")
243 +
" -fPIC -lvcsn '" + tmp +
".o' -shared" 244 +
" -o '" + tmp +
".so'" 250 std::string plugindir()
const 252 auto res =
xgetenv(
"VCSN_PLUGINDIR",
253 xgetenv(
"VCSN_HOME",
"~/.vcsn") +
"/plugins");
260 std::string
split(
const std::string& s)
const 262 auto res = std::string{};
263 const size_t size = 150;
264 for (
unsigned i = 0; i < s.length(); i +=
size)
268 res += s.substr(i, size);
281 void jit(
const std::string& base)
283 auto tmp = tmpname(base);
285 namespace chr = std::chrono;
286 using clock = chr::steady_clock;
287 auto start = clock::now();
288 static bool no_python = !!getenv(
"VCSN_NO_PYTHON");
293 boost::filesystem::rename(tmp +
".so", base +
".so");
298 if (!getenv(
"VCSN_DEBUG"))
299 boost::filesystem::remove(tmp +
".o");
305 xgetenv(
"VCSN",
"vcsn") +
" compile");
306 auto linkflags =
printer_.linkflags();
307 if (!linkflags.empty())
308 linkflags =
" LDFLAGS+='" + linkflags +
"'";
309 cxx(cmd +
" -shared" + linkflags +
" '" + base +
".cc'",
313 = chr::duration_cast<chr::milliseconds>(clock::now() - start);
314 if (getenv(
"VCSN_TIME"))
316 std::ofstream{
"/tmp/vcsn-compile.log",
319 << (no_python ?
"C++, " :
"Py, ")
320 <<
'\'' << base.substr(plugindir().
size()) <<
'\'' 322 if (getenv(
"VCSN_TIME2"))
323 std::cerr << d.count() <<
"ms: " << base <<
'\n';
334 void operator()(
const std::string& ctx)
336 printer_.header(
"vcsn/ctx/instantiate.hh");
337 auto base = plugindir() +
"contexts/" +
split(ctx);
345 " VCSN_CTX_INSTANTIATE(ctx_t);\n" 354 operator()(
const std::set<std::pair<std::string, signature>>& algos)
356 printer_.header(
"vcsn/misc/attributes.hh");
357 printer_.header(
"vcsn/dyn/name.hh");
358 printer_.header(
"vcsn/dyn/registries.hh");
359 for (
const auto& algo: algos)
363 for (
const auto& algo: algos)
366 <<
"// " << algo.first <<
'.';
369 for (
const auto& s: algo.second)
376 types += (first ?
"" :
", ") + t;
382 "static bool vcsn_" << algo.first <<
" ATTRIBUTE_USED =" 384 <<
"vcsn::dyn::detail::" << algo.first <<
"_register(" 386 <<
"vcsn::ssignature<" << types <<
">()," 388 <<
"vcsn::dyn::detail::" << algo.first <<
"<" << types <<
">" 395 auto base = (plugindir()
397 + begin(algos)->first +
"/" 398 +
split(begin(algos)->second.to_string()));
404 std::ostringstream
os;
413 auto translate = translation{};
416 catch (
const std::runtime_error& e)
418 raise(e,
" while compiling context ",
ctx);
424 auto algos = std::set<std::pair<std::string, signature>>{{algo, sig}};
425 if (algo ==
"delay_automaton" 426 || algo ==
"is_synchronized")
428 algos.emplace(
"delay_automaton", sig);
429 algos.emplace(
"is_synchronized", sig);
433 auto translate = translation{};
436 catch (
const std::runtime_error& e)
438 raise(e,
" while compiling ", algo,
" for ", sig);
std::ostream & iendl(std::ostream &o)
Print an end of line, then set the indentation.
polynomial split(const expression &exp)
Break exp.
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
std::string xgetenv(const std::string &var, const std::string &val="")
getenv(var) if defined, otherwise val.
xlt_advise & global(bool global)
Request the set implementation (bool weights).
std::shared_ptr< ast_node > parse_type(const std::string &type)
Parse a type, and return its AST.
std::string get_file_contents(const std::string &file)
Return the contents of file.
void compile(const std::string &ctx)
Compile, and load, a DSO with instantiations for ctx.
std::string expand_tilda(const std::string &res)
Expand initial "~" in res.
bool equal_files(const std::string &fn1, const std::string &fn2)
Whether two files have exactly equal contents.
std::shared_ptr< ast_node > parse_context(const std::string &ctx)
Parse a context, and return its AST.
std::ostringstream os
The output stream: the corresponding C++ snippet to compile.
std::shared_ptr< std::istream > open_input_file(const std::string &file)
Open file for reading and return its autoclosing stream.
std::ostream & print_context(const context &ctx, std::ostream &o, const std::string &fmt)
Bridge (print).
std::ostream & incendl(std::ostream &o)
Increment the indentation, print an end of line, and set the indentation.
weightset_mixin< detail::log_impl > log
std::ostream & decendl(std::ostream &o)
Decrement the indentation, print an end of line, and set the indentation.
std::string type(const automaton &a)
The implementation type of a.
jit_error(const std::string &assert, const std::string &what)
ast::context_printer printer_
std::string to_string(identities i)
Wrapper around operator<<.
Signature of a function call.
detail::config & get_config()
Get the configuration singleton.
std::ostream & print(const automaton &aut, std::ostream &out=std::cout, const std::string &format="default")
Print automaton a on out using format format.
xlt_handle open(const std::string &s)
std::string assertions
If defined, static assertions that failed (ends with a eol).
Indentation relative functions.
#define VCSN_REQUIRE(Cond,...)
A macro similar to require.
xlt_advise & verbose(int v)
Whether to report dlopen attempts.
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.