mCRL2
Loading...
Searching...
No Matches
uncompiledlibrary.h
Go to the documentation of this file.
1// Author(s): Jeroen Keiren, Sjoerd Cranen
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
12
13#ifndef MCRL2_UTILITY_UNCOMPILED_LIBRARY_H
14#define MCRL2_UTILITY_UNCOMPILED_LIBRARY_H
15
16/*
17 * Extends the dynamic_library from dynamiclibrary.h to be able to compile a
18 * source file and load the resulting library.
19 *
20 * Usage:
21 *
22 * uncompiled_library mylib;
23 * mylib.compile(source_filename);
24 * myfunc = mylib.proc_address("myfunc");
25 * myfunc(10);
26 *
27 * Remarks:
28 *
29 * The source is compiled using a script that must take two string arguments.
30 * The first argument is the source file, the second is the destination file.
31 * After (successful) termination, only the source and destination files must
32 * remain on disk -- it is the responsibility of the script to remove any
33 * temporary files.
34 *
35 */
36
38
39#ifndef MCRL2_PLATFORM_WINDOWS
40
41#include <cerrno>
42#include <list>
45
47{
48 protected:
49 std::list<std::string> m_tempfiles;
50 std::string m_compile_script;
51
53
54 public:
55 uncompiled_library(const std::string& script)
56 : m_compile_script(script)
57 {}
58
59 void compile(const std::string& filename)
60 {
61 std::stringstream commandline;
62 commandline << '"' << m_compile_script << "\" " << filename << " " << " 2>&1";
63
64 // Execute script.
65 FILE* stream = popen(commandline.str().c_str(), "r");
66 if (stream == nullptr)
67 {
68 throw std::runtime_error("Could not execute compile script.");
69 }
70
71 // Script produces one file per line. Last file is the shared library,
72 // preceding files are temporary files that should be removed when the
73 // library is unloaded.
74 std::string files;
75 char buf[1024];
76 while(!feof(stream))
77 {
78 if (fgets(buf, sizeof(buf), stream) != nullptr)
79 {
80 std::string line(buf);
81 assert(*line.rbegin() == '\n');
82 line.erase(line.size() - 1);
83 mCRL2log(mcrl2::log::debug) << " Read line: " << line << std::endl;
84
85 // Check that reported file exists. If not, produce error message and
86 // flush script output to the log.
88 {
89 mCRL2log(mcrl2::log::error) << "Compile script " << m_compile_script << " produced unexpected output:\n";
90 mCRL2log(mcrl2::log::error) << line << std::endl;
91 while (fgets(buf, sizeof(buf), stream) != nullptr)
92 {
93 mCRL2log(mcrl2::log::error) << std::string(buf);
94 }
95 pclose(stream);
96 throw std::runtime_error("Compile script failed.");
97 }
98 m_tempfiles.push_back(line);
99 }
100 else if(ferror(stream) && errno == EINTR)
101 {
102 // On OSX, interrupts sometimes arrive during the call to read(), which
103 // is called by fgets. If an interrupt arrives, we just ignore it
104 // an clear the error status of the stream, and try again.
105 mCRL2log(mcrl2::log::debug) << "Reading was interrupted. Clearing error status and retrying" << std::endl;
106 perror("Error according to errno");
107 clearerr(stream);
108 }
109 }
110
111 if (ferror(stream))
112 {
113 pclose(stream);
114 throw std::runtime_error("There was a problem reading the output of the compile script.");
115 }
116
117 pclose(stream);
118
119 m_filename = m_tempfiles.back();
120 }
121
123 {
124 m_tempfiles.clear();
125 }
126
127 void cleanup()
128 {
129 for(std::list<std::string>::iterator f = m_tempfiles.begin(); f != m_tempfiles.end(); ++f)
130 {
131 if (remove((*f).c_str()))
132 {
133 std::stringstream s;
134 s << "Could not remove file: " << *f;
135 throw std::runtime_error(s.str());
136 }
137 else
138 {
139 mCRL2log(mcrl2::log::debug) << "Temporary file '" << *f << "' deleted." << std::endl;
140 }
141 }
142 }
143
145 {
146#ifndef NDEBUG // In debug mode, the compiled rewriter has not been removed directly after loading,
147 // and we still have to remove it.
148 try
149 {
150 cleanup();
151 }
152 catch (std::runtime_error &error)
153 {
154 mCRL2log(mcrl2::log::error) << "Could not cleanup temporary files: " << error.what() << std::endl;
155 }
156#endif
157 }
158
159};
160
161#endif // MCRL2_PLATFORM_WINDOWS
162
163#endif // MCRL2_UTILITY_UNCOMPILED_LIBRARY_H
std::string m_filename
std::string m_compile_script
std::list< std::string > m_tempfiles
uncompiled_library()=delete
void compile(const std::string &filename)
uncompiled_library(const std::string &script)
add your file description here.
@ error
Definition linearise.cpp:68
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391
bool file_exists(const std::string &filename)