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::targetLibDir
56  = "LIB = $(PWD)/../platforms/$(WM_OPTIONS)/lib";
57 
58 const char* const Foam::dynamicCode::topDirName
59  = "dynamicCode";
60 
61 
62 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
63 
65 (
66  const char* title,
67  const dictionary& dict
68 )
69 {
70  if (isAdministrator())
71  {
73  << "This code should not be executed by someone"
74  << " with administrator rights for security reasons." << nl
75  << "It generates a shared library which is loaded using dlopen"
76  << nl << endl
77  << exit(FatalIOError);
78  }
79 
80  if (!allowSystemOperations)
81  {
83  << "Loading shared libraries using case-supplied code may have"
84  << " been disabled" << nl
85  << "by default for security reasons." << nl
86  << "If you trust the code, you may enable this by adding"
87  << nl << nl
88  << " allowSystemOperations 1" << nl << nl
89  << "to the InfoSwitches setting in the system controlDict." << nl
90  << "The system controlDict is any of" << nl << nl
91  << " ~/.OpenFOAM/" << foamVersion::api << "/controlDict" << nl
92  << " ~/.OpenFOAM/controlDict" << nl
93  << " $WM_PROJECT_DIR/etc/controlDict" << nl << endl
94  << exit(FatalIOError);
95  }
96 }
97 
98 
99 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
100 
102 (
103  ISstream& is,
104  OSstream& os,
105  const HashTable<string>& mapping
106 )
107 {
108  if (!is.good())
109  {
111  << "Failed opening for reading " << is.name()
112  << exit(FatalError);
113  }
114 
115  if (!os.good())
116  {
118  << "Failed writing " << os.name()
119  << exit(FatalError);
120  }
121 
122  // Copy file while rewriting $VARS and ${VARS}
123  string line;
124  do
125  {
126  is.getLine(line);
127 
128  // Expand according to HashTable mapping, not the environment.
129  // Expanding according to env variables might cause too many
130  // surprises
131  stringOps::inplaceExpand(line, mapping);
132  os.writeQuoted(line, false) << nl;
133  }
134  while (is.good());
135 }
136 
137 
139 (
140  const UList<fileName>& templateNames,
141  DynamicList<fileName>& resolvedFiles,
142  DynamicList<fileName>& badFiles
143 )
144 {
145  // Try to get template from FOAM_CODE_TEMPLATES
146  const fileName templateDir(Foam::getEnv(codeTemplateEnvName));
147 
148  bool allOkay = true;
149  for (const fileName& templateName : templateNames)
150  {
151  fileName file;
152  if (!templateDir.empty() && isDir(templateDir))
153  {
154  file = templateDir/templateName;
155  if (!isFile(file, false))
156  {
157  file.clear();
158  }
159  }
160 
161  // Not found - fallback to <etc> expansion
162  if (file.empty())
163  {
164  file = findEtcFile(codeTemplateDirName/templateName);
165  }
166 
167  if (file.empty())
168  {
169  badFiles.append(templateName);
170  allOkay = false;
171  }
172  else
173  {
174  resolvedFiles.append(file);
175  }
176  }
177 
178  return allOkay;
179 }
180 
181 
183 {
184  const auto fnd = filterVars_.cfind("SHA1sum");
185 
186  if (!fnd.found())
187  {
188  return false;
189  }
190 
191  os << "/* dynamicCode:\n * SHA1 = ";
192  os.writeQuoted(*fnd, false) << "\n */\n";
193  return true;
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 
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;
284 
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  }
302 
303  clear();
304 }
305 
306 
307 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
308 
310 {
311  return topDirName/codeDirName_;
312 }
313 
314 
316 {
317  return codeRoot_/libSubDir_/dlLibraryTable::fullname(codeName_);
318 }
319 
320 
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 
352 
354 {
355  compileFiles_.append(name);
356 }
357 
358 
360 {
361  copyFiles_.append(name);
362 }
363 
364 
366 (
367  const fileName& name,
368  const string& contents
369 )
370 {
371  createFiles_.append(fileAndContent(name, contents));
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 
396 
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 fileAndContent& 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();
488 
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 
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 
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 
531 {
532  return upToDate(context.sha1());
533 }
534 
535 
536 // ************************************************************************* //
Foam::dynamicCodeContext::localCode
const string & localCode() const noexcept
The local (file-scope) code.
Definition: dynamicCodeContext.H:152
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:197
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:182
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:65
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:73
Foam::dynamicCode::copyAndFilter
static void copyAndFilter(ISstream &, OSstream &, const HashTable< string > &mapping)
Copy lines while expanding variables.
Definition: dynamicCode.C:102
Foam::SHA1::str
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1I.H:122
Foam::dynamicCode::copyOrCreateFiles
bool copyOrCreateFiles(const bool verbose=false) const
Copy/create files prior to compilation.
Definition: dynamicCode.C:403
Foam::fileName::path
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:176
Foam::dynamicCode::wmakeLibso
bool wmakeLibso() const
Compile a libso.
Definition: dynamicCode.C:495
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::OBJstream::writeQuoted
virtual Ostream & writeQuoted(const std::string &str, const bool quoted=true)
Write std::string surrounded by quotes.
Definition: OBJstream.C:108
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:199
Foam::system
int system(const std::string &command, const bool bg=false)
Execute the specified command via the shell.
Definition: MSwindows.C:1150
Foam::dynamicCode::createMakeOptions
bool createMakeOptions() const
Copy/create Make/options prior to compilation.
Definition: dynamicCode.C:235
Foam::dynamicCode::writeDigest
bool writeDigest(const SHA1Digest &) const
Write digest to Make/SHA1Digest.
Definition: dynamicCode.C:264
Foam::glTF::key
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:108
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:369
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:376
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:139
Foam::dynamicCode::addCopyFile
void addCopyFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:359
Foam::getEnv
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: MSwindows.C:371
Foam::IOstream::good
bool good() const noexcept
True if next operation might succeed.
Definition: IOstream.H:233
Foam::dynamicCode::allowSystemOperations
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:166
Foam::dynamicCodeContext::sha1
const SHA1 & sha1() const noexcept
The SHA1 calculated from options, libs, include, code, etc.
Definition: dynamicCodeContext.H:164
Foam::isAdministrator
bool isAdministrator()
Is the current user the administrator (root)
Definition: MSwindows.C:442
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:315
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:353
Foam::stringOps::inplaceExpand
void inplaceExpand(std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:731
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 (stdout output on master, null elsewhere)
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:511
argList.H
Foam::dynamicCode::checkSecurity
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:65
Foam::dynamicCode::codeRelPath
fileName codeRelPath() const
Path for specified code name relative to <case>
Definition: dynamicCode.C:309
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:321
DetailInfo
#define DetailInfo
Definition: evalEntry.C:37
Foam::ISstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: ISstream.H:113
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::dynamicCode::targetLibDir
static const char *const targetLibDir
Directory for library targets for Make/files.
Definition: dynamicCode.H:111
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:123
os
OBJstream os(runTime.globalPath()/outputName)
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:388
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:344
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::include
const string & include() const noexcept
The code includes.
Definition: dynamicCodeContext.H:146
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:530
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::dynamicCode::setMakeOptions
void setMakeOptions(const std::string &content)
Define contents for Make/options.
Definition: dynamicCode.C:397
clear
patchWriters clear()
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Fstream.H
Foam::dynamicCode::clear
void clear()
Clear files and variables.
Definition: dynamicCode.C:327
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:53
Foam::name
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
Foam::dynamicCodeContext::code
const string & code() const noexcept
The code.
Definition: dynamicCodeContext.H:158
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: stringOps.H:60
Foam::stringOps::expand
string expand(const std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:718
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:366
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
foamVersion.H