11 #include <boost/filesystem.hpp>
18 #include <vcsn/config.hh>
33 :
std::runtime_error(what)
41 xgetenv(
const std::string& var,
const std::string& val =
"")
43 const char* cp = getenv(var.c_str());
47 #define XGETENV(Name) xgetenv(#Name, Name)
51 std::string expand_tilda(std::string res)
53 if (!res.empty() && res[0] ==
'~')
55 assert(res.size() == 1 || res[1] ==
'/');
56 auto home = xgetenv(
"HOME", xgetenv(
"USERPROFILE"));
57 char const *hdrive = getenv(
"HOMEDRIVE");
58 char const *hres = getenv(
"HOMERES");
60 res.replace(0, 1, home);
61 else if (hdrive && hres)
62 res.replace(0, 1, std::string(hdrive) + hres);
64 res.replace(0, 1, xgetenv(
"VCSN_TMPDIR",
"/tmp"));
70 void ensure_parent_directory(
const std::string& path)
72 boost::filesystem::path p(path);
73 boost::filesystem::create_directories(p.parent_path());
77 std::string tmpname(std::string res)
97 void print(
const std::string& base)
99 ensure_parent_directory(base);
102 auto tmp = tmpname(base);
104 std::ofstream o{tmp +
".cc"};
107 boost::filesystem::rename(tmp +
".cc", base +
".cc");
116 auto ast =
parser_.parse_context();
121 void print_type(
const std::string&
type)
132 void throw_compiler_errors(std::string cmd,
133 const std::string& err)
152 static auto r1 = std::regex{
"static assertion failed: (.*)$",
153 std::regex::extended};
154 static auto r2 = std::regex{
"static_assert failed \"(.*)\"$",
155 std::regex::extended};
158 std::string assertions;
159 while (std::getline(*
is, line))
160 if (std::regex_search(line, smatch, r1)
161 || std::regex_search(line, smatch, r2))
162 assertions += std::string(smatch[1]) +
'\n';
163 if (getenv(
"VCSN_VERBOSE"))
165 cmd +=
"\n compiler error messages:\n";
168 throw jit_error(assertions,
" failed command:\n " + cmd);
175 void cxx(std::string cmd,
const std::string& tmp)
177 auto err = tmp +
".err";
178 if (getenv(
"VCSN_DEBUG"))
179 std::cerr <<
"run: " << cmd << std::endl;
180 if (system((cmd +
" 2>'" + err +
"'").c_str()))
181 throw_compiler_errors(cmd, err);
185 std::ifstream
log{err};
186 std::cerr <<
log.rdbuf();
191 boost::filesystem::remove(err);
198 void cxx_compile(
const std::string& base)
200 auto tmp = tmpname(base);
203 auto cmd = (std::string{
"LC_ALL=C"}
208 +
" -fPIC '" + base +
".cc' -c"
209 +
" -o '" + tmp +
".o'");
216 void cxx_link(
const std::string& base)
218 auto tmp = tmpname(base);
219 auto cmd = (std::string{
"LC_ALL=C"}
223 +
" -fPIC -lvcsn '" + tmp +
".o' -shared"
224 +
" -o '" + tmp +
".so'"
230 std::string plugindir()
const
232 auto res = xgetenv(
"VCSN_PLUGINDIR",
233 xgetenv(
"VCSN_HOME",
"~/.vcsn") +
"/plugins");
234 res = expand_tilda(res);
240 std::string
split(
const std::string& s)
const
243 const size_t size = 150;
244 for (
unsigned i = 0; i < s.length(); i +=
size)
248 res += s.substr(i, size);
261 void jit(
const std::string& base)
263 auto tmp = tmpname(base);
265 namespace chr = std::chrono;
266 using clock = chr::steady_clock;
267 auto start = clock::now();
268 static bool no_python = !!getenv(
"VCSN_NO_PYTHON");
273 boost::filesystem::rename(tmp +
".so", base +
".so");
278 if (!getenv(
"VCSN_DEBUG"))
279 boost::filesystem::remove(tmp +
".o");
283 auto linkflags =
printer_.linkflags();
284 if (!linkflags.empty())
285 linkflags =
" --extra-ldflags='" + linkflags +
"'";
286 cxx(
"vcsn compile -shared '" + base +
".cc'" + linkflags,
290 = chr::duration_cast<chr::milliseconds>(clock::now() - start);
291 if (getenv(
"VCSN_TIME"))
293 std::ofstream{
"/tmp/vcsn-compile.log",
296 << (no_python ?
"C++, " :
"Py, ")
297 <<
'\'' << base.substr(plugindir().
size()) <<
'\''
299 if (getenv(
"VCSN_TIME2"))
300 std::cerr << d.count() <<
"ms: " << base <<
'\n';
303 static bool first =
true;
309 lt_dlhandle lib = lt_dlopen((base +
".so").c_str());
310 VCSN_REQUIRE(lib,
"cannot load lib: ", base,
".so: ", lt_dlerror());
314 void compile(
const std::string& ctx)
316 printer_.header(
"vcsn/ctx/instantiate.hh");
318 plugindir() +
"contexts/" +
split(ctx);
326 " VCSN_CTX_INSTANTIATE(ctx_t);\n"
336 printer_.header(
"vcsn/misc/attributes.hh");
337 printer_.header(
"vcsn/misc/name.hh");
338 printer_.header(
"vcsn/dyn/registries.hh");
339 for (
const auto& algo: algos)
343 for (
const auto& algo: algos)
346 <<
"// " << algo.first <<
'.';
349 for (
const auto& s: algo.second)
356 types += (first ?
"" :
", ") + t;
362 "static bool " << algo.first <<
" ATTRIBUTE_USED =" <<
incendl
363 <<
"vcsn::dyn::detail::" << algo.first <<
"_register(" <<
incendl
364 <<
"vcsn::ssignature<" << types <<
">()," <<
iendl
365 <<
"vcsn::dyn::detail::" << algo.first <<
"<" << types <<
">" <<
decendl
371 std::string base = (plugindir()
373 + begin(algos)->first +
"/"
374 +
split(begin(algos)->second.to_string()));
380 std::istringstream
is;
382 std::ostringstream
os;
390 translation translate;
391 translate.compile(ctx);
396 translation translate;
397 std::set<std::pair<std::string, signature>> algos{{algo, sig}};
398 if (algo ==
"delay_automaton"
399 || algo ==
"is_synchronized")
401 algos.emplace(
"delay_automaton", sig);
402 algos.emplace(
"is_synchronized", sig);
404 translate.compile(algos);
std::shared_ptr< std::istream > open_input_file(const std::string &file)
Open file for reading and return its autoclosing stream.
std::ostream & incendl(std::ostream &o)
Increment the indentation, print an end of line, and set the indentation.
#define VCSN_REQUIRE(Cond,...)
A macro similar to require.
ast::context_parser parser_
Request the set implementation (bool weights).
std::ostringstream os
The output stream: the corresponding C++ snippet to compile.
std::ostream & decendl(std::ostream &o)
Decrement the indentation, print an end of line, and set the indentation.
jit_error(const std::string &assert, const std::string &what)
std::string type(const automaton &a)
The implementation type of a.
Indentation relative functions.
std::ostream & iendl(std::ostream &o)
Print an end of line, then set the indentation.
weightset_mixin< detail::log_impl > log
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
ast::context_printer printer_
std::ostream & print(const automaton &aut, std::ostream &out, const std::string &format="default")
Print automaton a on o using format format.
std::string get_file_contents(const std::string &file)
Return the contents of file.
std::istringstream is
The input stream: the specification to translate.
static dyn::context ctx(const driver &d)
Get the context of the driver.
std::string to_string(identities i)
Wrapper around operator<<.
std::ostream & print_context(const context &ctx, std::ostream &o, const std::string &fmt)
Bridge (print).
polynomial split(const expression &exp)
Break exp.
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
void compile(const std::string &ctx)
Compile, and load, a DSO with instantiations for ctx.
Signature of a function call.