Loading...
Searching...
No Matches
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-------------------------------------------------------------------------------
11License
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"
36// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38namespace Foam
39{
40namespace functionEntries
41{
43
45 (
48 execute,
49 dictionaryIstream,
51 );
52
54 (
57 execute,
58 primitiveEntryIstream,
60 );
61} // End namespace functionEntries
62} // End namespace Foam
63
64
65// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
66
68(
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
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 {
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 (
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{
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}
287
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// ************************************************************************* //
Input/output from string buffers.
Macros for easy insertion into member function selection tables.
#define addNamedToMemberFunctionSelectionTable(baseType, thisType, funcName, argNames, lookupName)
Add to hash-table of functions with 'lookupName' as the key.
const Time & time() const noexcept
Return Time associated with the objectRegistry.
Definition IOobject.C:456
static float fileModificationSkew
Time skew (seconds) for file modification checks.
Definition IOobject.H:363
streamFormat format() const noexcept
Get the current stream format.
label lineNumber() const noexcept
Const access to the current stream line number.
Definition IOstream.H:409
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition Istream.H:60
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with '_' prefix.
Definition SHA1I.H:114
dlLibraryTable & libs() const noexcept
Mutable access to the loaded dynamic libraries.
Definition Time.H:722
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition UPstream.H:1069
baseIOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO function...
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
const dictionary & topDict() const
Return the top of the tree.
Definition dictionary.C:185
fileName relativeName(const bool caseTag=false) const
The dictionary name relative to the case.
Definition dictionary.C:179
bool read(Istream &is)
Read dictionary from Istream (discards the header). Reads entries until EOF or when the first token i...
A table of dynamically loaded libraries.
Encapsulation of dynamic code dictionaries.
const string & libs() const noexcept
The code libs (LIB_LIBS).
const SHA1 & sha1() const noexcept
The SHA1 calculated from options, libs, include, code, etc.
const string & options() const noexcept
The code options (Make/options).
const dictionary & dict() const noexcept
Return the parent dictionary context.
Tools for handling dynamic code compilation.
Definition dynamicCode.H:57
bool copyOrCreateFiles(const bool verbose=false) const
Copy/create files prior to compilation.
void reset(const dynamicCodeContext &)
Clear files and reset variables to specified context.
fileName libRelPath() const
Library path for specified code name relative to <case>.
static void waitForFile(const fileName &file, const dictionary &contextDict)
Wait for libPath() file to appear on sub-ranks.
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition dynamicCode.C:59
void addCompileFile(const fileName &name)
Add a file template name, which will be found and filtered.
bool upToDate(const dynamicCodeContext &context) const
Verify if the copied code is up-to-date, based on Make/SHA1Digest.
fileName libPath() const
Library path for specified code name.
bool wmakeLibso() const
Compile a libso.
void setMakeOptions(const std::string &content)
Define contents for Make/options.
const word & codeName() const noexcept
Return the code-name.
entry(const keyType &keyword)
Construct from keyword.
Definition entry.C:62
A class for handling file names.
Definition fileName.H:75
Dictionary entry that contains C++ OpenFOAM code that is compiled to generate the entry itself....
Definition codeStream.H:118
static bool doingMasterOnlyReading(const dictionary &dict)
Helper: access IOobject for master-only-reading functionality.
Definition codeStream.C:70
static streamingFunctionType getFunction(const dictionary &parentDict, const dictionary &codeDict)
Construct, compile, load and return streaming function.
Definition codeStream.C:95
static bool execute(const dictionary &parentDict, primitiveEntry &entry, Istream &is)
Execute in a primitiveEntry context.
Definition codeStream.C:287
void(* streamingFunctionType)(Ostream &, const dictionary &)
Interpreter function type.
Definition codeStream.H:124
static string evaluate(const dictionary &parentDict, Istream &is)
Evaluate dynamically compiled code, returning result as string.
Definition codeStream.C:255
static dlLibraryTable & libs(const dictionary &dict)
Helper function: access to dlLibraryTable of Time.
Definition codeStream.C:61
static constexpr const char *const codeTemplateC
Name of the C code template to be used.
Definition codeStream.H:160
A functionEntry causes entries to be added/manipulated on the specified dictionary given an input str...
primitiveEntry(const keyType &key)
Construct from keyword and no tokens.
virtual const dictionary & dict() const
This entry is not a dictionary, calling this function generates a FatalError.
static bool masterOnlyReading
To flag master-only reading of objects.
Definition regIOobject.H:86
A class for handling character strings derived from std::string.
Definition string.H:76
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition error.H:629
#define DetailInfo
Definition evalEntry.C:30
OBJstream os(runTime.globalPath()/outputName)
#define DebugPout
Report an information message using Foam::Pout.
Namespace for containing a functionEntry.
Definition calcEntry.C:33
Namespace for OpenFOAM.
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler().
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
void * dlOpen(const fileName &libName, const bool check=true)
Open a shared library and return handle to library.
Definition POSIX.C:1826
void * dlSym(void *handle, const std::string &symbol)
Lookup a symbol in a dlopened library using handle to library.
Definition OSspecific.H:440
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
dictionary dict