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-2020 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 "IOstreams.H"
36 #include "OSspecific.H"
37 #include "etcFiles.H"
38 #include "dictionary.H"
39 #include "foamVersion.H"
40 
41 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 
44 (
45  Foam::debug::infoSwitch("allowSystemOperations", 0)
46 );
47 
48 
50  = "FOAM_CODE_TEMPLATES";
51 
53  = "codeTemplates/dynamicCode";
54 
55 const char* const Foam::dynamicCode::libTargetRoot =
56  "LIB = $(PWD)/../platforms/$(WM_OPTIONS)/lib/lib";
57 
58 const char* const Foam::dynamicCode::topDirName = "dynamicCode";
59 
60 
61 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
62 
64 (
65  const char* title,
66  const dictionary& dict
67 )
68 {
69  if (isAdministrator())
70  {
72  << "This code should not be executed by someone"
73  << " with administrator rights for security reasons." << nl
74  << "It generates a shared library which is loaded using dlopen"
75  << nl << endl
76  << exit(FatalIOError);
77  }
78 
79  if (!allowSystemOperations)
80  {
82  << "Loading shared libraries using case-supplied code may have"
83  << " been disabled" << nl
84  << "by default for security reasons." << nl
85  << "If you trust the code, you may enable this by adding"
86  << nl << nl
87  << " allowSystemOperations 1" << nl << nl
88  << "to the InfoSwitches setting in the system controlDict." << nl
89  << "The system controlDict is any of" << nl << nl
90  << " ~/.OpenFOAM/" << foamVersion::api << "/controlDict" << nl
91  << " ~/.OpenFOAM/controlDict" << nl
92  << " $WM_PROJECT_DIR/etc/controlDict" << nl << endl
93  << exit(FatalIOError);
94  }
95 }
96 
97 
98 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
99 
101 (
102  ISstream& is,
103  OSstream& os,
104  const HashTable<string>& mapping
105 )
106 {
107  if (!is.good())
108  {
110  << "Failed opening for reading " << is.name()
111  << exit(FatalError);
112  }
113 
114  if (!os.good())
115  {
117  << "Failed writing " << os.name()
118  << exit(FatalError);
119  }
120 
121  // Copy file while rewriting $VARS and ${VARS}
122  string line;
123  do
124  {
125  is.getLine(line);
126 
127  // Expand according to HashTable mapping, not the environment.
128  // Expanding according to env variables might cause too many
129  // surprises
130  stringOps::inplaceExpand(line, mapping);
131  os.writeQuoted(line, false) << nl;
132  }
133  while (is.good());
134 }
135 
136 
138 (
139  const UList<fileName>& templateNames,
140  DynamicList<fileName>& resolvedFiles,
141  DynamicList<fileName>& badFiles
142 )
143 {
144  // Try to get template from FOAM_CODE_TEMPLATES
145  const fileName templateDir(Foam::getEnv(codeTemplateEnvName));
146 
147  bool allOkay = true;
148  for (const fileName& templateName : templateNames)
149  {
150  fileName file;
151  if (!templateDir.empty() && isDir(templateDir))
152  {
153  file = templateDir/templateName;
154  if (!isFile(file, false))
155  {
156  file.clear();
157  }
158  }
159 
160  // Not found - fallback to <etc> expansion
161  if (file.empty())
162  {
163  file = findEtcFile(codeTemplateDirName/templateName);
164  }
165 
166  if (file.empty())
167  {
168  badFiles.append(templateName);
169  allOkay = false;
170  }
171  else
172  {
173  resolvedFiles.append(file);
174  }
175  }
176 
177  return allOkay;
178 }
179 
180 
182 {
183  const auto fnd = filterVars_.cfind("SHA1sum");
184 
185  if (!fnd.found())
186  {
187  return false;
188  }
189 
190  os << "/* dynamicCode:\n * SHA1 = ";
191  os.writeQuoted(*fnd, false) << "\n */\n";
192  return true;
193 }
194 
195 
197 {
198  // Create Make/files
199  if (compileFiles_.empty())
200  {
201  return false;
202  }
203 
204  const fileName dstFile(this->codePath()/"Make/files");
205 
206  // Create dir
207  mkDir(dstFile.path());
208 
209  OFstream os(dstFile);
210  //Debug: Info<< "Writing to " << dstFile << endl;
211  if (!os.good())
212  {
214  << "Failed writing " << dstFile
215  << exit(FatalError);
216  }
217 
218  writeCommentSHA1(os);
219 
220  // Write compile files
221  for (const fileName& file : compileFiles_)
222  {
223  os.writeQuoted(file, false) << nl;
224  }
225 
226  os << nl
227  << libTargetRoot << codeName_.c_str() << nl;
228 
229  return true;
230 }
231 
232 
234 {
235  // Create Make/options
236  if (compileFiles_.empty() || makeOptions_.empty())
237  {
238  return false;
239  }
240 
241  const fileName dstFile(this->codePath()/"Make/options");
242 
243  // Create dir
244  mkDir(dstFile.path());
245 
246  OFstream os(dstFile);
247  //Debug: Info<< "Writing to " << dstFile << endl;
248  if (!os.good())
249  {
251  << "Failed writing " << dstFile
252  << exit(FatalError);
253  }
254 
255  writeCommentSHA1(os);
256  os.writeQuoted(makeOptions_, false) << nl;
257 
258  return true;
259 }
260 
261 
263 {
264  const fileName file = digestFile();
265  mkDir(file.path());
266 
267  OFstream os(file);
268  sha1.write(os, true) << nl;
269 
270  return os.good();
271 }
272 
273 
274 bool Foam::dynamicCode::writeDigest(const std::string& sha1) const
275 {
276  const fileName file = digestFile();
277  mkDir(file.path());
278 
279  OFstream os(file);
280  os << '_';
281  os.writeQuoted(sha1, false) << nl;
282 
283  return os.good();
284 }
285 
286 
287 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
288 
289 Foam::dynamicCode::dynamicCode(const word& codeName, const word& codeDirName)
290 :
291  codeRoot_(argList::envGlobalPath()/topDirName),
292  libSubDir_(stringOps::expand("platforms/${WM_OPTIONS}/lib")),
293  codeName_(codeName),
294  codeDirName_(codeDirName)
295 {
296  if (codeDirName_.empty())
297  {
298  codeDirName_ = codeName_;
299  }
300 
301  clear();
302 }
303 
304 
305 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
306 
308 {
309  return topDirName/codeDirName_;
310 }
311 
312 
314 {
315  return codeRoot_/libSubDir_/dlLibraryTable::fullname(codeName_);
316 }
317 
318 
320 {
321  return codeRelPath()/libSubDir_/dlLibraryTable::fullname(codeName_);
322 }
323 
324 
326 {
327  compileFiles_.clear();
328  copyFiles_.clear();
329  createFiles_.clear();
330  filterVars_.clear();
331  filterVars_.set("typeName", codeName_);
332  filterVars_.set("SHA1sum", SHA1Digest().str());
333 
334  // Default Make/options
335  makeOptions_ =
336  "EXE_INC = -g\n"
337  "\n\nLIB_LIBS = ";
338 }
339 
340 
342 (
343  const dynamicCodeContext& context
344 )
345 {
346  clear();
347  setFilterContext(context);
348 }
349 
350 
352 {
353  compileFiles_.append(name);
354 }
355 
356 
358 {
359  copyFiles_.append(name);
360 }
361 
362 
364 (
365  const fileName& name,
366  const string& contents
367 )
368 {
369  createFiles_.append(fileAndContent(name, contents));
370 }
371 
372 
374 (
375  const dynamicCodeContext& context
376 )
377 {
378  filterVars_.set("localCode", context.localCode());
379  filterVars_.set("code", context.code());
380  filterVars_.set("codeInclude", context.include());
381  filterVars_.set("SHA1sum", context.sha1().str());
382 }
383 
384 
386 (
387  const word& key,
388  const std::string& value
389 )
390 {
391  filterVars_.set(key, value);
392 }
393 
394 
395 void Foam::dynamicCode::setMakeOptions(const std::string& content)
396 {
397  makeOptions_ = content;
398 }
399 
400 
401 bool Foam::dynamicCode::copyOrCreateFiles(const bool verbose) const
402 {
403  if (verbose)
404  {
405  DetailInfo
406  << "Creating new library in " << this->libRelPath() << endl;
407  }
408 
409  const label nFiles = compileFiles_.size() + copyFiles_.size();
410 
411  DynamicList<fileName> resolvedFiles(nFiles);
412  DynamicList<fileName> badFiles(nFiles);
413 
414  // Resolve template, or add to bad-files
415  resolveTemplates(compileFiles_, resolvedFiles, badFiles);
416  resolveTemplates(copyFiles_, resolvedFiles, badFiles);
417 
418  if (!badFiles.empty())
419  {
421  << "Could not find code template(s): "
422  << badFiles << nl
423  << "Under the $" << codeTemplateEnvName
424  << " directory or via the <etc>/"
425  << codeTemplateDirName << " expansion"
426  << exit(FatalError);
427  }
428 
429 
430 
431  // Create dir
432  const fileName outputDir = this->codePath();
433 
434  // Create dir
435  mkDir(outputDir);
436 
437  // Copy/filter files
438  for (const fileName& srcFile : resolvedFiles)
439  {
440  const fileName dstFile(outputDir/srcFile.name());
441 
442  IFstream is(srcFile);
443  //Debug: Info<< "Reading from " << is.name() << endl;
444  if (!is.good())
445  {
447  << "Failed opening " << srcFile
448  << exit(FatalError);
449  }
450 
451  OFstream os(dstFile);
452  //Debug: Info<< "Writing to " << dstFile.name() << endl;
453  if (!os.good())
454  {
456  << "Failed writing " << dstFile
457  << exit(FatalError);
458  }
459 
460  // Copy lines while expanding variables
461  copyAndFilter(is, os, filterVars_);
462  }
463 
464 
465  // Create files:
466  for (const fileAndContent& content : createFiles_)
467  {
468  const fileName dstFile(outputDir/stringOps::expand(content.first()));
469 
470  mkDir(dstFile.path());
471  OFstream os(dstFile);
472  //Debug: Info<< "Writing to " << content.first() << endl;
473  if (!os.good())
474  {
476  << "Failed writing " << dstFile
477  << exit(FatalError);
478  }
479  os.writeQuoted(content.second(), false) << nl;
480  }
481 
482 
483  // Create Make/files + Make/options
484  createMakeFiles();
485  createMakeOptions();
486 
487  writeDigest(filterVars_["SHA1sum"]);
488 
489  return true;
490 }
491 
492 
494 {
495  stringList cmd({"wmake", "-s", "libso", this->codePath()});
496 
497  // NOTE: could also resolve wmake command explicitly
498  // cmd[0] = stringOps::expand("$WM_PROJECT_DIR/wmake/wmake");
499 
500  // This can take a bit longer, so report that we are starting wmake
501  // Even with details turned off, we want some feedback
502 
503  OSstream& os = (Foam::infoDetailLevel > 0 ? Info : Serr);
504  os << "Invoking wmake libso " << this->codePath().c_str() << endl;
505 
506  if (Foam::system(cmd) == 0)
507  {
508  return true;
509  }
510 
511  return false;
512 }
513 
514 
516 {
517  const fileName file = digestFile();
518 
519  if (!exists(file, false) || SHA1Digest(IFstream(file)()) != sha1)
520  {
521  return false;
522  }
523 
524  return true;
525 }
526 
527 
529 {
530  return upToDate(context.sha1());
531 }
532 
533 
534 // ************************************************************************* //
OSspecific.H
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
IOstreams.H
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
Foam::dynamicCode::createMakeFiles
bool createMakeFiles() const
Copy/create Make/files prior to compilation.
Definition: dynamicCode.C:196
Foam::exists
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: MSwindows.C:625
Foam::dynamicCode::topDirName
static const char *const topDirName
Top-level directory name for copy/compiling.
Definition: dynamicCode.H:114
Foam::dynamicCode::writeCommentSHA1
bool writeCommentSHA1(Ostream &) const
Write SHA1 value as C-comment.
Definition: dynamicCode.C:181
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::ISstream::getLine
ISstream & getLine(std::string &str, char delim='\n')
Raw, low-level getline (until delimiter) into a string.
Definition: ISstreamI.H:76
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::dynamicCode::copyAndFilter
static void copyAndFilter(ISstream &, OSstream &, const HashTable< string > &mapping)
Copy lines while expanding variables.
Definition: dynamicCode.C:101
Foam::SHA1::str
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1I.H:123
Foam::dynamicCode::copyOrCreateFiles
bool copyOrCreateFiles(const bool verbose=false) const
Copy/create files prior to compilation.
Definition: dynamicCode.C:401
Foam::fileName::path
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:186
Foam::dynamicCode::wmakeLibso
bool wmakeLibso() const
Compile a libso.
Definition: dynamicCode.C:493
Foam::IFstream
Input from file stream, using an ISstream.
Definition: IFstream.H:53
Foam::DynamicList
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:55
Foam::dynamicCodeContext
Encapsulation of dynamic code dictionaries.
Definition: dynamicCodeContext.H:53
Foam::fileName::name
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:209
Foam::system
int system(const std::string &command, const bool bg=false)
Execute the specified command via the shell.
Definition: MSwindows.C:1140
Foam::Ostream::writeQuoted
virtual Ostream & writeQuoted(const std::string &str, const bool quoted=true)=0
Write std::string surrounded by quotes.
Foam::dynamicCode::createMakeOptions
bool createMakeOptions() const
Copy/create Make/options prior to compilation.
Definition: dynamicCode.C:233
Foam::OSstream::writeQuoted
virtual Ostream & writeQuoted(const std::string &str, const bool quoted=true)
Write std::string surrounded by quotes.
Definition: OSstream.C:113
Foam::dynamicCode::writeDigest
bool writeDigest(const SHA1Digest &) const
Write digest to Make/SHA1Digest.
Definition: dynamicCode.C:262
Foam::ISstream
Generic input stream using a standard (STL) stream.
Definition: ISstream.H:55
Foam::argList
Extract command arguments and options from the supplied argc and argv parameters.
Definition: argList.H:123
Foam::isFile
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: MSwindows.C:658
Foam::FatalIOError
IOerror FatalIOError
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::dynamicCodeContext::include
const string & include() const
Return the code-includes.
Definition: dynamicCodeContext.H:134
Foam::Serr
OSstream Serr
OSstream wrapped stderr (std::cerr)
dynamicCodeContext.H
Foam::dynamicCode::setFilterContext
void setFilterContext(const dynamicCodeContext &)
Define filter variables for code, codeInclude, SHA1sum.
Definition: dynamicCode.C:374
Foam::dynamicCode::resolveTemplates
static bool resolveTemplates(const UList< fileName > &templateNames, DynamicList< fileName > &resolvedFiles, DynamicList< fileName > &badFiles)
Resolve code-templates via the codeTemplateEnvName.
Definition: dynamicCode.C:138
Foam::dynamicCode::addCopyFile
void addCopyFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:357
Foam::getEnv
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: MSwindows.C:371
Foam::dynamicCode::allowSystemOperations
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:166
Foam::isAdministrator
bool isAdministrator()
Is the current user the administrator (root)
Definition: MSwindows.C:442
Foam::stringOps::expand
string expand(const std::string &s, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Definition: stringOps.C:720
Foam::debug::infoSwitch
int infoSwitch(const char *name, const int deflt=0)
Lookup info switch or add default value.
Definition: debug.C:231
Foam::dynamicCode::libPath
fileName libPath() const
Library path for specified code name.
Definition: dynamicCode.C:313
Foam::dynamicCode::codeTemplateEnvName
static const word codeTemplateEnvName
Name of the code template environment variable.
Definition: dynamicCode.H:159
Foam::dynamicCode::addCompileFile
void addCompileFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:351
Foam::foamVersion::api
const int api
Foam::SHA1Digest::write
Ostream & write(Ostream &os, const bool prefixed=false) const
Write (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1Digest.C:156
Foam::findEtcFile
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:446
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::OSstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:107
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:474
argList.H
Foam::dynamicCodeContext::code
const string & code() const
Return the code.
Definition: dynamicCodeContext.H:152
Foam::dynamicCode::checkSecurity
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:64
Foam::dynamicCode::codeRelPath
fileName codeRelPath() const
Path for specified code name relative to <case>
Definition: dynamicCode.C:307
Foam::stringOps::inplaceExpand
void inplaceExpand(std::string &s, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Definition: stringOps.C:733
dynamicCode.H
Foam::OSstream
Generic output stream using a standard (STL) stream.
Definition: OSstream.H:54
Foam::dynamicCode::libRelPath
fileName libRelPath() const
Library path for specified code name relative to <case>
Definition: dynamicCode.C:319
DetailInfo
#define DetailInfo
Definition: evalEntry.C:36
Foam::ISstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: ISstream.H:124
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam::SHA1Digest
The SHA1 message digest.
Definition: SHA1Digest.H:60
Foam::dynamicCode::setFilterVariable
void setFilterVariable(const word &key, const std::string &value)
Define a filter variable.
Definition: dynamicCode.C:386
Foam::infoDetailLevel
int infoDetailLevel
Global for selective suppression of Info output.
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:53
Foam::dynamicCode::reset
void reset(const dynamicCodeContext &)
Clear files and reset variables to specified context.
Definition: dynamicCode.C:342
Foam::HashTable
A HashTable similar to std::unordered_map.
Definition: HashTable.H:105
etcFiles.H
Functions to search 'etc' directories for configuration files etc.
Foam::dynamicCodeContext::localCode
const string & localCode() const
Return the local (file-scope) code.
Definition: dynamicCodeContext.H:158
Foam::dynamicCode::upToDate
bool upToDate(const dynamicCodeContext &context) const
Verify if the copied code is up-to-date, based on Make/SHA1Digest.
Definition: dynamicCode.C:528
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:381
Foam::dynamicCode::setMakeOptions
void setMakeOptions(const std::string &content)
Define contents for Make/options.
Definition: dynamicCode.C:395
clear
patchWriters clear()
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Fstream.H
Foam::dynamicCode::clear
void clear()
Clear files and variables.
Definition: dynamicCode.C:325
Foam::List< string >
Foam::dynamicCode::codeTemplateDirName
static const fileName codeTemplateDirName
Name of the code template sub-directory.
Definition: dynamicCode.H:163
dlLibraryTable.H
Foam::dlLibraryTable::fullname
static word fullname(word libName)
Library fullname, prefix with 'lib', suffix with '.so'.
Definition: dlLibraryTable.C:68
Foam::UList
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:103
dictionary.H
Foam::line
A line primitive.
Definition: line.H:59
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:401
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
Foam::Tuple2
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition: Tuple2.H:57
Foam::IOstream::good
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:224
Foam::dynamicCodeContext::sha1
const SHA1 & sha1() const
Return SHA1 calculated from options, libs, include, code.
Definition: dynamicCodeContext.H:164
Foam::mkDir
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: MSwindows.C:507
stringOps.H
Foam::dynamicCode::addCreateFile
void addCreateFile(const fileName &name, const string &contents)
Add a file to create with its contents. Will not be filtered.
Definition: dynamicCode.C:364
Foam::isDir
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: MSwindows.C:643
Foam::dynamicCode::libTargetRoot
static const char *const libTargetRoot
Root of the LIB target for Make/files.
Definition: dynamicCode.H:111
foamVersion.H