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 to distributed masters
200  if (fileHandler().distributed())
201  {
202  fileHandler().broadcastCopy
203  (
205  UPstream::master(fileHandler().comm()),
206  libPath,
207  libPath
208  );
209  }
210 
211  dynamicCode::waitForFile(libPath, context.dict());
212  }
213 
214  if (!lib)
215  {
216  if (isA<baseIOdictionary>(topDict))
217  {
218  lib = libs(parentDict).open(libPath, false);
219  }
220  else
221  {
222  lib = Foam::dlOpen(libPath, false);
223  }
224  }
225 
226 
227  if (masterOnly ? !lib : returnReduceOr(!lib))
228  {
229  FatalIOErrorInFunction(parentDict)
230  << "Failed loading library " << dynCode.libRelPath()
231  << " on some processors."
232  << "Did you add all libraries to the 'libs' entry"
233  << " in system/controlDict?"
234  << exit(FatalIOError);
235  }
236 
237 
238  // Find the function handle in the library
239  streamingFunctionType function =
240  reinterpret_cast<streamingFunctionType>
241  (
242  Foam::dlSym(lib, dynCode.codeName())
243  );
244 
245 
246  if (!function)
247  {
248  FatalIOErrorInFunction(parentDict)
249  << "Failed looking up symbol " << dynCode.codeName()
250  << " in library " << dynCode.libRelPath()
251  << exit(FatalIOError);
252  }
253 
254  return function;
255 }
256 
257 
259 (
260  const dictionary& parentDict,
261  Istream& is
262 )
263 {
264  DetailInfo
265  << "Using #codeStream at line " << is.lineNumber()
266  << " in file " << parentDict.relativeName() << endl;
267 
269  (
270  "functionEntries::codeStream::evaluate(..)",
271  parentDict
272  );
273 
274  // Get code dictionary
275  dictionary codeDict("#codeStream", parentDict, is);
276 
277  // Use function to write stream
278  OStringStream os(is.format());
279 
280  streamingFunctionType function = getFunction(parentDict, codeDict);
281  (*function)(os, parentDict);
282 
283  // Return evaluated content as string
284  return os.str();
285 }
286 
288 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
289 
291 (
292  const dictionary& parentDict,
294  Istream& is
295 )
296 {
297  IStringStream result(evaluate(parentDict, is));
298  entry.read(parentDict, result);
299 
300  return true;
301 }
302 
303 
305 (
306  dictionary& parentDict,
307  Istream& is
308 )
309 {
310  IStringStream result(evaluate(parentDict, is));
311  parentDict.read(result);
312 
313  return true;
314 }
315 
316 
317 // ************************************************************************* //
dictionary dict
A class for handling file names.
Definition: fileName.H:72
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:348
bool read(Istream &is)
Read dictionary from Istream (discards the header). Reads entries until EOF or when the first token i...
Definition: dictionaryIO.C:134
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
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:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler()
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:409
static string evaluate(const dictionary &parentDict, Istream &is)
Evaluate dynamically compiled code, returning result as string.
Definition: codeStream.C:255
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:287
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, calling this function generates a FatalError.
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:84
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:627
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:1082
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 ...