dynamicCode.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-2016 OpenFOAM Foundation
9  Copyright (C) 2016-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 "dynamicCode.H"
30 #include "dynamicCodeContext.H"
31 #include "dlLibraryTable.H"
32 #include "argList.H"
33 #include "stringOps.H"
34 #include "Fstream.H"
35 #include "IOobject.H"
36 #include "IOstreams.H"
37 #include "OSspecific.H"
38 #include "etcFiles.H"
39 #include "dictionary.H"
40 #include "foamVersion.H"
41 
42 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 
45 (
46  Foam::debug::infoSwitch("allowSystemOperations", 0)
47 );
48 
49 
51  = "FOAM_CODE_TEMPLATES";
52 
54  = "codeTemplates/dynamicCode";
55 
56 const char* const Foam::dynamicCode::targetLibDir
57  = "LIB = $(PWD)/../platforms/$(WM_OPTIONS)/lib";
58 
60  = "dynamicCode";
61 
62 
63 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
64 
66 (
67  const char* title,
68  const dictionary& dict
69 )
70 {
71  if (isAdministrator())
72  {
74  << "This code should not be executed by someone"
75  << " with administrator rights for security reasons." << nl
76  << "It generates a shared library which is loaded using dlopen"
77  << nl << endl
78  << exit(FatalIOError);
79  }
80 
82  {
84  << "Loading shared libraries using case-supplied code may have"
85  << " been disabled" << nl
86  << "by default for security reasons." << nl
87  << "If you trust the code, you may enable this by adding"
88  << nl << nl
89  << " allowSystemOperations 1" << nl << nl
90  << "to the InfoSwitches setting in the system controlDict." << nl
91  << "The system controlDict is any of" << nl << nl
92  << " ~/.OpenFOAM/" << foamVersion::api << "/controlDict" << nl
93  << " ~/.OpenFOAM/controlDict" << nl
94  << " $WM_PROJECT_DIR/etc/controlDict" << nl << endl
95  << exit(FatalIOError);
96  }
97 }
98 
99 
100 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
101 
103 (
104  ISstream& is,
105  OSstream& os,
106  const HashTable<string>& mapping
107 )
108 {
109  if (!is.good())
110  {
112  << "Failed opening for reading " << is.name()
113  << exit(FatalError);
114  }
115 
116  if (!os.good())
117  {
119  << "Failed writing " << os.name()
120  << exit(FatalError);
121  }
122 
123  // Copy file while rewriting $VARS and ${VARS}
124  string line;
125  do
126  {
127  is.getLine(line);
128 
129  // Expand according to HashTable mapping, not the environment.
130  // Expanding according to env variables might cause too many
131  // surprises
132  stringOps::inplaceExpand(line, mapping);
133  os.writeQuoted(line, false) << nl;
134  }
135  while (is.good());
136 }
137 
138 
140 (
141  const UList<fileName>& templateNames,
142  DynamicList<fileName>& resolvedFiles,
143  DynamicList<fileName>& badFiles
144 )
145 {
146  // Try to get template from FOAM_CODE_TEMPLATES
147  const fileName templateDir(Foam::getEnv(codeTemplateEnvName));
148 
149  bool allOkay = true;
150  for (const fileName& templateName : templateNames)
151  {
152  fileName file;
153  if (!templateDir.empty() && isDir(templateDir))
154  {
155  file = templateDir/templateName;
156  if (!isFile(file, false))
157  {
158  file.clear();
159  }
160  }
161 
162  // Not found - fallback to <etc> expansion
163  if (file.empty())
164  {
165  file = findEtcFile(codeTemplateDirName/templateName);
166  }
167 
168  if (file.empty())
169  {
170  badFiles.push_back(templateName);
171  allOkay = false;
172  }
173  else
174  {
175  resolvedFiles.push_back(file);
176  }
177  }
178 
179  return allOkay;
180 }
181 
182 
183 bool Foam::dynamicCode::writeCommentSHA1(Ostream& os) const
184 {
185  const auto iter = filterVars_.cfind("SHA1sum");
186 
187  if (iter.good())
188  {
189  os << "/* dynamicCode:\n * SHA1 = ";
190  os.writeQuoted(iter.val(), false) << "\n */\n";
191  }
192 
193  return iter.good();
194 }
195 
196 
198 {
199  // Create Make/files
200  if (compileFiles_.empty())
201  {
202  return false;
203  }
204 
205  const fileName dstFile(this->codePath()/"Make/files");
206 
207  // Create dir
208  mkDir(dstFile.path());
209 
210  OFstream os(dstFile);
211  //Debug: Info<< "Writing to " << dstFile << endl;
212  if (!os.good())
213  {
215  << "Failed writing " << dstFile
216  << exit(FatalError);
217  }
218 
219  writeCommentSHA1(os);
220 
221  // Write compile files
222  for (const fileName& file : compileFiles_)
223  {
224  os.writeQuoted(file, false) << nl;
225  }
226 
227  os << nl
228  << targetLibDir
229  << "/lib" << codeName_.c_str() << nl;
230 
231  return true;
232 }
233 
234 
236 {
237  // Create Make/options
238  if (compileFiles_.empty() || makeOptions_.empty())
239  {
240  return false;
241  }
242 
243  const fileName dstFile(this->codePath()/"Make/options");
244 
245  // Create dir
246  mkDir(dstFile.path());
247 
248  OFstream os(dstFile);
249  //Debug: Info<< "Writing to " << dstFile << endl;
250  if (!os.good())
251  {
253  << "Failed writing " << dstFile
254  << exit(FatalError);
255  }
256 
257  writeCommentSHA1(os);
258  os.writeQuoted(makeOptions_, false) << nl;
259 
260  return true;
261 }
262 
263 
264 bool Foam::dynamicCode::writeDigest(const SHA1Digest& sha1) const
265 {
266  const fileName file = digestFile();
267  mkDir(file.path());
268 
269  OFstream os(file);
270  sha1.write(os, true) << nl;
271 
272  return os.good();
273 }
274 
275 
276 bool Foam::dynamicCode::writeDigest(const std::string& sha1) const
277 {
278  const fileName file = digestFile();
279  mkDir(file.path());
280 
281  OFstream os(file);
282  os << '_';
283  os.writeQuoted(sha1, false) << nl;
285  return os.good();
286 }
287 
288 
289 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
290 
291 Foam::dynamicCode::dynamicCode(const word& codeName, const word& codeDirName)
292 :
293  codeRoot_(argList::envGlobalPath()/topDirName),
294  libSubDir_(stringOps::expand("platforms/${WM_OPTIONS}/lib")),
295  codeName_(codeName),
296  codeDirName_(codeDirName)
297 {
298  if (codeDirName_.empty())
299  {
300  codeDirName_ = codeName_;
301  }
303  clear();
304 }
305 
306 
307 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
310 {
311  return topDirName/codeDirName_;
312 }
313 
316 {
317  return codeRoot_/libSubDir_/dlLibraryTable::fullname(codeName_);
318 }
319 
322 {
323  return codeRelPath()/libSubDir_/dlLibraryTable::fullname(codeName_);
324 }
325 
326 
328 {
329  compileFiles_.clear();
330  copyFiles_.clear();
331  createFiles_.clear();
332  filterVars_.clear();
333  filterVars_.set("typeName", codeName_);
334  filterVars_.set("SHA1sum", SHA1Digest().str());
335 
336  // Default Make/options
337  makeOptions_ =
338  "EXE_INC = -g\n"
339  "\n\nLIB_LIBS = ";
340 }
341 
342 
344 (
345  const dynamicCodeContext& context
346 )
347 {
348  clear();
349  setFilterContext(context);
350 }
351 
354 {
355  compileFiles_.push_back(name);
356 }
357 
358 
360 {
361  copyFiles_.push_back(name);
362 }
363 
364 
366 (
367  const fileName& name,
368  const std::string& fileContents
369 )
370 {
371  createFiles_.emplace_back(name, fileContents);
372 }
373 
374 
376 (
377  const dynamicCodeContext& context
378 )
379 {
380  filterVars_.set("localCode", context.localCode());
381  filterVars_.set("code", context.code());
382  filterVars_.set("codeInclude", context.include());
383  filterVars_.set("SHA1sum", context.sha1().str());
384 }
385 
386 
388 (
389  const word& key,
390  const std::string& value
391 )
392 {
393  filterVars_.set(key, value);
394 }
395 
397 void Foam::dynamicCode::setMakeOptions(const std::string& content)
398 {
399  makeOptions_ = content;
400 }
401 
402 
403 bool Foam::dynamicCode::copyOrCreateFiles(const bool verbose) const
404 {
405  if (verbose)
406  {
407  DetailInfo
408  << "Creating new library in " << this->libRelPath() << endl;
409  }
410 
411  const label nFiles = compileFiles_.size() + copyFiles_.size();
412 
413  DynamicList<fileName> resolvedFiles(nFiles);
414  DynamicList<fileName> badFiles(nFiles);
415 
416  // Resolve template, or add to bad-files
417  resolveTemplates(compileFiles_, resolvedFiles, badFiles);
418  resolveTemplates(copyFiles_, resolvedFiles, badFiles);
419 
420  if (!badFiles.empty())
421  {
423  << "Could not find code template(s): "
424  << badFiles << nl
425  << "Under the $" << codeTemplateEnvName
426  << " directory or via the <etc>/"
427  << codeTemplateDirName << " expansion"
428  << exit(FatalError);
429  }
430 
431 
432 
433  // Create dir
434  const fileName outputDir = this->codePath();
435 
436  // Create dir
437  mkDir(outputDir);
438 
439  // Copy/filter files
440  for (const fileName& srcFile : resolvedFiles)
441  {
442  const fileName dstFile(outputDir/srcFile.name());
443 
444  IFstream is(srcFile);
445  //Debug: Info<< "Reading from " << is.name() << endl;
446  if (!is.good())
447  {
449  << "Failed opening " << srcFile
450  << exit(FatalError);
451  }
452 
453  OFstream os(dstFile);
454  //Debug: Info<< "Writing to " << dstFile.name() << endl;
455  if (!os.good())
456  {
458  << "Failed writing " << dstFile
459  << exit(FatalError);
460  }
461 
462  // Copy lines while expanding variables
463  copyAndFilter(is, os, filterVars_);
464  }
465 
466 
467  // Create files:
468  for (const auto& content : createFiles_)
469  {
470  const fileName dstFile(outputDir/stringOps::expand(content.first()));
471 
472  mkDir(dstFile.path());
473  OFstream os(dstFile);
474  //Debug: Info<< "Writing to " << content.first() << endl;
475  if (!os.good())
476  {
478  << "Failed writing " << dstFile
479  << exit(FatalError);
480  }
481  os.writeQuoted(content.second(), false) << nl;
482  }
483 
484 
485  // Create Make/files + Make/options
486  createMakeFiles();
487  createMakeOptions();
489  writeDigest(filterVars_["SHA1sum"]);
490 
491  return true;
492 }
493 
494 
496 {
497  stringList cmd({"wmake", "-s", "libso", this->codePath()});
498 
499  // NOTE: could also resolve wmake command explicitly
500  // cmd[0] = stringOps::expand("$WM_PROJECT_DIR/wmake/wmake");
501 
502  // This can take a bit longer, so report that we are starting wmake
503  // Even with details turned off, we want some feedback
504 
505  OSstream& os = (Foam::infoDetailLevel > 0 ? Info : InfoErr);
506  os << "Invoking wmake libso " << this->codePath().c_str() << endl;
507 
508  if (Foam::system(cmd) == 0)
509  {
510  return true;
511  }
512 
513  return false;
514 }
515 
516 
517 bool Foam::dynamicCode::upToDate(const SHA1Digest& sha1) const
518 {
519  const fileName file = digestFile();
520 
521  if (!exists(file, false) || SHA1Digest(IFstream(file)()) != sha1)
522  {
523  return false;
524  }
525 
526  return true;
527 }
528 
529 
530 bool Foam::dynamicCode::upToDate(const dynamicCodeContext& context) const
531 {
532  return upToDate(context.sha1());
533 }
534 
535 
536 // * * * * * * * * * * * * * * * Synchronisation * * * * * * * * * * * * * * //
537 
539 (
540  const fileName& file,
541  const dictionary& contextDict
542 )
543 {
544  const int debug = 0;
545 
546  if (!UPstream::parRun())
547  {
548  return;
549  }
550 
551  // If library has just been compiled on the master, the other nodes
552  // need to pick this library up through NFS, which likely has delays
553  // in it.
554 
555  // We do this by just polling a few times using the
556  // fileModificationSkew.
557 
558  off_t localSize = Foam::fileSize(file);
559  off_t masterSize = localSize;
560  Pstream::broadcast(masterSize);
561 
562  for
563  (
564  label iter = 0;
565  (
568  );
569  ++iter
570  )
571  {
572  DebugPout
573  << "Processor " << UPstream::myProcNo()
574  << " masterSize:" << masterSize
575  << " localSize:" << localSize << endl;
576 
577  if (localSize == masterSize)
578  {
579  return;
580  }
581  if (localSize > masterSize)
582  {
583  FatalIOErrorInFunction(contextDict)
584  << "Excessive size when reading (NFS mounted) library "
585  << nl << file << nl
586  << "on processor " << UPstream::myProcNo()
587  << " detected size " << localSize
588  << " whereas master size is " << masterSize
589  << " bytes." << nl
590  << "If your case is NFS mounted increase"
591  << " fileModificationSkew or maxFileModificationPolls;"
592  << nl << "If your case is not NFS mounted"
593  << " (so distributed) set fileModificationSkew"
594  << " to 0"
595  << exit(FatalIOError);
596  }
597  else
598  {
599  DebugPout
600  << "Local file " << file
601  << " not of same size (" << localSize
602  << ") as master ("
603  << masterSize << "). Waiting for "
605  << " seconds." << endl;
606 
608 
609  // Recheck local size
610  localSize = Foam::fileSize(file);
611  }
612  }
613 
614  // Finished doing iterations. Do final check
615  if (localSize != masterSize)
616  {
617  FatalIOErrorInFunction(contextDict)
618  << "Cannot read (NFS mounted) library:" << nl
619  << file << nl
620  << "on processor " << UPstream::myProcNo()
621  << " detected size " << localSize
622  << " whereas master size is " << masterSize
623  << " bytes." << nl
624  << "If your case is NFS mounted increase"
625  << " fileModificationSkew or maxFileModificationPolls;" << nl
626  << "If your case is not NFS mounted"
627  << " (so distributed) set fileModificationSkew"
628  << " to 0"
629  << exit(FatalIOError);
630  }
631 
632  DebugPout
633  << "Processor " << UPstream::myProcNo()
634  << " masterSize:" << masterSize
635  << " localSize:" << localSize
636  << " ... after waiting" << endl;
637 }
638 
639 
640 // ************************************************************************* //
const string & include() const noexcept
The code includes.
dictionary dict
const string & localCode() const noexcept
The local (file-scope) code.
bool writeDigest(const SHA1Digest &) const
Write digest to Make/SHA1Digest.
Definition: dynamicCode.C:257
A line primitive.
Definition: line.H:52
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
void addCreateFile(const fileName &name, const std::string &contents)
Add a file to create with its contents. Will not be filtered.
Definition: dynamicCode.C:359
off_t fileSize(const fileName &name, const bool followLink=true)
Return size of file or -1 on failure (normally follows symbolic links).
Definition: POSIX.C:905
void reset(const dynamicCodeContext &)
Clear files and reset variables to specified context.
Definition: dynamicCode.C:337
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
static float fileModificationSkew
Time skew (seconds) for file modification checks.
Definition: IOobject.H:348
messageStream InfoErr
Information stream (stderr output on master, null elsewhere)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
void setMakeOptions(const std::string &content)
Define contents for Make/options.
Definition: dynamicCode.C:390
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
virtual const fileName & name() const override
Read/write access to the name of the stream.
Definition: OSstream.H:128
static void waitForFile(const fileName &file, const dictionary &contextDict)
Wait for libPath() file to appear on sub-ranks.
Definition: dynamicCode.C:532
Output to file stream, using an OSstream.
Definition: OFstream.H:49
int infoDetailLevel
Global for selective suppression of Info output.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
static bool resolveTemplates(const UList< fileName > &templateNames, DynamicList< fileName > &resolvedFiles, DynamicList< fileName > &badFiles)
Resolve code-templates via the codeTemplateEnvName.
Definition: dynamicCode.C:133
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
The SHA1 message digest.
Definition: SHA1Digest.H:56
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1049
void setFilterContext(const dynamicCodeContext &)
Define filter variables for code, codeInclude, SHA1sum.
Definition: dynamicCode.C:369
static const word codeTemplateEnvName
Name of the code template environment variable.
Definition: dynamicCode.H:181
static const char *const topDirName
Top-level directory name for copy/compiling.
Definition: dynamicCode.H:118
static const char *const targetLibDir
Directory for library targets for Make/files.
Definition: dynamicCode.H:113
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:169
void addCompileFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:346
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: POSIX.C:339
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1074
int infoSwitch(const char *name, const int deflt=0)
Lookup info switch or add default value.
Definition: debug.C:228
bool writeCommentSHA1(Ostream &) const
Write SHA1 value as C-comment.
Definition: dynamicCode.C:176
bool createMakeOptions() const
Copy/create Make/options prior to compilation.
Definition: dynamicCode.C:228
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
fileName codeRelPath() const
Path for specified code name relative to <case>
Definition: dynamicCode.C:302
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:860
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:614
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
fileName libRelPath() const
Library path for specified code name relative to <case>
Definition: dynamicCode.C:314
A class for handling words, derived from Foam::string.
Definition: word.H:63
Functions to search &#39;etc&#39; directories for configuration files etc.
static const fileName codeTemplateDirName
Name of the code template sub-directory.
Definition: dynamicCode.H:188
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:118
virtual Ostream & writeQuoted(const char *str, std::streamsize len, const bool quoted=true) override
Write character/string content, with/without surrounding quotes.
Definition: OBJstream.C:78
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:193
static void copyAndFilter(ISstream &, OSstream &, const HashTable< string > &mapping)
Copy lines while expanding variables.
Definition: dynamicCode.C:96
static int maxFileModificationPolls
Max number of times to poll for file modification changes.
Definition: IOobject.H:353
static word fullname(word libName)
Library fullname, prefix with &#39;lib&#39;, suffix with &#39;.so&#39;.
bool exists(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist (as DIRECTORY or FILE) in the file system?
Definition: POSIX.C:835
patchWriters clear()
bool wmakeLibso() const
Compile a libso.
Definition: dynamicCode.C:488
#define DetailInfo
Definition: evalEntry.C:30
const int api
OpenFOAM api number (integer) corresponding to the value of OPENFOAM at the time of compilation...
unsigned int sleep(const unsigned int sec)
Sleep for the specified number of seconds.
Definition: POSIX.C:1547
void inplaceExpand(std::string &s, const HashTable< string > &mapping, const char sigil='$')
Inplace expand occurrences of variables according to the mapping. Does not use environment values...
Definition: stringOps.C:718
bool upToDate(const dynamicCodeContext &context) const
Verify if the copied code is up-to-date, based on Make/SHA1Digest.
Definition: dynamicCode.C:523
int debug
Static debugging option.
bool copyOrCreateFiles(const bool verbose=false) const
Copy/create files prior to compilation.
Definition: dynamicCode.C:396
OBJstream os(runTime.globalPath()/outputName)
const string & code() const noexcept
The code.
bool isAdministrator()
Is the current user the administrator (root)
Definition: POSIX.C:434
bool isFile(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist as a FILE in the file system?
Definition: POSIX.C:877
Encapsulation of dynamic code dictionaries.
Ostream & write(Ostream &os, const bool prefixed=false) const
Write (40-byte) text representation, optionally with &#39;_&#39; prefix.
Definition: SHA1Digest.C:252
void setFilterVariable(const word &key, const std::string &value)
Define a filter variable.
Definition: dynamicCode.C:381
fileName findEtcFile(const fileName &name, const bool mandatory=false, unsigned short location=0777)
Search for a single FILE within the etc directories.
Definition: etcFiles.C:439
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:627
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
bool good() const noexcept
True if next operation might succeed.
Definition: IOstream.H:281
void addCopyFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:352
#define DebugPout
Report an information message using Foam::Pout.
fileName libPath() const
Library path for specified code name.
Definition: dynamicCode.C:308
messageStream Info
Information stream (stdout output on master, null elsewhere)
void clear()
Clear files and variables.
Definition: dynamicCode.C:320
dynamicCode(const dynamicCode &)=delete
No copy construct.
int system(const std::string &command, const bool bg=false)
Execute the specified command via the shell.
Definition: POSIX.C:1702
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:59
bool createMakeFiles() const
Copy/create Make/files prior to compilation.
Definition: dynamicCode.C:190
const SHA1 & sha1() const noexcept
The SHA1 calculated from options, libs, include, code, etc.
string expand(const std::string &s, const HashTable< string > &mapping, const char sigil='$')
Expand occurrences of variables according to the mapping and return the expanded string.
Definition: stringOps.C:705
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...