codeStream.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2018-2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "codeStream.H"
30 #include "dynamicCode.H"
31 #include "dynamicCodeContext.H"
32 #include "StringStream.H"
33 #include "Time.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40 namespace functionEntries
41 {
42  defineTypeNameAndDebug(codeStream, 0);
43 
45  (
46  functionEntry,
47  codeStream,
48  execute,
49  dictionaryIstream,
50  codeStream
51  );
52 
54  (
55  functionEntry,
56  codeStream,
57  execute,
58  primitiveEntryIstream,
59  codeStream
60  );
61 } // End namespace functionEntries
62 } // End namespace Foam
63 
64 
65 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
66 
68 (
69  const dictionary& dict
70 )
71 {
72  return static_cast<const baseIOdictionary&>(dict.topDict()).time().libs();
73 }
74 
75 
77 (
78  const dictionary& dict
79 )
80 {
81  // Fallback value
82  bool masterOnly = regIOobject::masterOnlyReading;
83 
84  const auto* rioPtr = isA<regIOobject>(dict.topDict());
85 
86  if (rioPtr)
87  {
88  masterOnly = rioPtr->global();
89  }
90 
91  DebugPout
92  << "codeStream : " << (rioPtr ? "IO" : "plain")
93  << " dictionary:" << dict.name()
94  << " master-only-reading:" << masterOnly << endl;
95 
96  return masterOnly;
97 }
98 
99 
102 (
103  const dictionary& parentDict,
104  const dictionary& codeDict
105 )
106 {
107  // get code, codeInclude, codeOptions
108  dynamicCodeContext context(codeDict);
109 
110  // codeName: codeStream + _<sha1>
111  // codeDir : _<sha1>
112  std::string sha1Str(context.sha1().str(true));
113  dynamicCode dynCode("codeStream" + sha1Str, sha1Str);
114 
115 
116  const dictionary& topDict = parentDict.topDict();
117  const bool masterOnly = doingMasterOnlyReading(topDict);
118 
119  // Load library if not already loaded
120  // Version information is encoded in the libPath (encoded with the SHA1)
121  const fileName libPath = dynCode.libPath();
122 
123  // See if library is loaded
124  void* lib = nullptr;
125 
126  if (isA<baseIOdictionary>(topDict))
127  {
128  lib = libs(parentDict).findLibrary(libPath);
129  }
130 
131  // nothing loaded
132  // avoid compilation if possible by loading an existing library
133  if (!lib)
134  {
135  DetailInfo
136  << "Using #codeStream with " << libPath << endl;
137 
138  if (isA<baseIOdictionary>(topDict))
139  {
140  // Cached access to libs, with cleanup upon termination
141  lib = libs(parentDict).open(libPath, false);
142  }
143  else
144  {
145  // Uncached opening of libPath. Do not complain if cannot be loaded
146  lib = Foam::dlOpen(libPath, false);
147  }
148  }
149 
150 
151  // Indicates NFS filesystem
152  const bool isNFS = (IOobject::fileModificationSkew > 0);
153 
154  // Create library if required
155  if
156  (
157  lib == nullptr
158  && (UPstream::master() || !isNFS)
159  && !dynCode.upToDate(context)
160  )
161  {
162  // Filter with this context
163  dynCode.reset(context);
164 
165  // Compile filtered C template
166  dynCode.addCompileFile(codeTemplateC);
167 
168  // define Make/options
169  dynCode.setMakeOptions
170  (
171  "EXE_INC = -g \\\n"
172  + context.options()
173  + "\n\nLIB_LIBS = \\\n"
174  " -lOpenFOAM \\\n"
175  + context.libs()
176  );
177 
178  if (!dynCode.copyOrCreateFiles(true))
179  {
180  FatalIOErrorInFunction(parentDict)
181  << "Failed writing files for" << nl
182  << dynCode.libRelPath() << nl
183  << exit(FatalIOError);
184  }
185 
186  if (!dynCode.wmakeLibso())
187  {
188  FatalIOErrorInFunction(parentDict)
189  << "Failed wmake " << dynCode.libRelPath() << nl
190  << exit(FatalIOError);
191  }
192  }
193 
194 
195  //- Only block if we're not doing master-only reading.
196  // (flag set by regIOobject::read, baseIOdictionary constructor)
197  if (!masterOnly && returnReduceOr(lib == nullptr))
198  {
199  // Broadcast distributed...
200 
201  dynamicCode::waitForFile(libPath, context.dict());
202  }
203 
204  if (!lib)
205  {
206  if (isA<baseIOdictionary>(topDict))
207  {
208  lib = libs(parentDict).open(libPath, false);
209  }
210  else
211  {
212  lib = Foam::dlOpen(libPath, false);
213  }
214  }
215 
216 
217  if (masterOnly ? !lib : returnReduceOr(!lib))
218  {
219  FatalIOErrorInFunction(parentDict)
220  << "Failed loading library " << dynCode.libRelPath()
221  << " on some processors."
222  << "Did you add all libraries to the 'libs' entry"
223  << " in system/controlDict?"
224  << exit(FatalIOError);
225  }
226 
227 
228  // Find the function handle in the library
229  streamingFunctionType function =
230  reinterpret_cast<streamingFunctionType>
231  (
232  Foam::dlSym(lib, dynCode.codeName())
233  );
234 
235 
236  if (!function)
237  {
238  FatalIOErrorInFunction(parentDict)
239  << "Failed looking up symbol " << dynCode.codeName()
240  << " in library " << dynCode.libRelPath()
241  << exit(FatalIOError);
242  }
243 
244  return function;
245 }
246 
247 
249 (
250  const dictionary& parentDict,
251  Istream& is
252 )
253 {
254  DetailInfo
255  << "Using #codeStream at line " << is.lineNumber()
256  << " in file " << parentDict.relativeName() << endl;
257 
259  (
260  "functionEntries::codeStream::evaluate(..)",
261  parentDict
262  );
263 
264  // Get code dictionary
265  dictionary codeDict("#codeStream", parentDict, is);
266 
267  // Use function to write stream
268  OStringStream os(is.format());
269 
270  streamingFunctionType function = getFunction(parentDict, codeDict);
271  (*function)(os, parentDict);
272 
273  // Return evaluated content as string
274  return os.str();
275 }
276 
278 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
279 
281 (
282  const dictionary& parentDict,
284  Istream& is
285 )
286 {
287  IStringStream result(evaluate(parentDict, is));
288  entry.read(parentDict, result);
289 
290  return true;
291 }
292 
293 
295 (
296  dictionary& parentDict,
297  Istream& is
298 )
299 {
300  IStringStream result(evaluate(parentDict, is));
301  parentDict.read(result);
302 
303  return true;
304 }
305 
306 
307 // ************************************************************************* //
dictionary dict
A class for handling file names.
Definition: fileName.H:71
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with &#39;_&#39; prefix.
Definition: SHA1I.H:114
baseIOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO function...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
defineTypeNameAndDebug(codeStream, 0)
static float fileModificationSkew
Time skew (seconds) for file modification checks.
Definition: IOobject.H:331
bool read(Istream &is)
Read dictionary from Istream. Discards the header.
Definition: dictionaryIO.C:134
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
static bool doingMasterOnlyReading(const dictionary &dict)
Helper: access IOobject for master-only-reading functionality.
Definition: codeStream.C:70
Input/output from string buffers.
static void waitForFile(const fileName &file, const dictionary &contextDict)
Wait for libPath() file to appear on sub-ranks.
Definition: dynamicCode.C:532
static streamingFunctionType getFunction(const dictionary &parentDict, const dictionary &codeDict)
Construct, compile, load and return streaming function.
Definition: codeStream.C:95
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static string evaluate(const dictionary &parentDict, Istream &is)
Evaluate dynamically compiled code, returning result as string.
Definition: codeStream.C:245
void(* streamingFunctionType)(Ostream &, const dictionary &)
Interpreter function type.
Definition: codeStream.H:124
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read...
const dictionary & dict() const noexcept
Return the parent dictionary context.
static bool execute(const dictionary &parentDict, primitiveEntry &entry, Istream &is)
Execute in a primitiveEntry context.
Definition: codeStream.C:277
const string & options() const noexcept
The code options (Make/options)
string evaluate(label fieldWidth, const std::string &s, size_t pos=0, size_t len=std::string::npos)
String evaluation with specified (positive, non-zero) field width.
const dictionary & topDict() const
Return the top of the tree.
Definition: dictionary.C:185
#define DetailInfo
Definition: evalEntry.C:30
A table of dynamically loaded libraries.
OBJstream os(runTime.globalPath()/outputName)
virtual const dictionary & dict() const
This entry is not a dictionary,.
fileName relativeName(const bool caseTag=false) const
The dictionary name relative to the case.
Definition: dictionary.C:179
label lineNumber() const noexcept
Const access to the current stream line number.
Definition: IOstream.H:390
static bool masterOnlyReading
To flag master-only reading of objects.
Definition: regIOobject.H:83
Tools for handling dynamic code compilation.
Definition: dynamicCode.H:56
Encapsulation of dynamic code dictionaries.
void * dlSym(void *handle, const std::string &symbol)
Lookup a symbol in a dlopened library using handle to library.
Definition: OSspecific.H:440
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:607
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
Definition: StringStream.H:120
void * dlOpen(const fileName &libName, const bool check=true)
Open a shared library and return handle to library.
Definition: POSIX.C:1824
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1037
Macros for easy insertion into member function selection tables.
const string & libs() const noexcept
The code libs (LIB_LIBS)
#define DebugPout
Report an information message using Foam::Pout.
static dlLibraryTable & libs(const dictionary &dict)
Helper function: access to dlLibraryTable of Time.
Definition: codeStream.C:61
addNamedToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream, calc)
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:59
A class for handling character strings derived from std::string.
Definition: string.H:72
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
Definition: StringStream.H:256
streamFormat format() const noexcept
Get the current stream format.
Namespace for OpenFOAM.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:63
const SHA1 & sha1() const noexcept
The SHA1 calculated from options, libs, include, code, etc.
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...