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-------------------------------------------------------------------------------
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 "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
55const char* const Foam::dynamicCode::targetLibDir
56 = "LIB = $(PWD)/../platforms/$(WM_OPTIONS)/lib";
57
58const 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
78 }
79
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
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
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
276bool 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
291Foam::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
397void Foam::dynamicCode::setMakeOptions(const std::string& content)
398{
399 makeOptions_ = content;
400}
401
402
403bool Foam::dynamicCode::copyOrCreateFiles(const bool verbose) const
404{
405 if (verbose)
406 {
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// ************************************************************************* //
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
bool upToDate() const
Access to the up-to-date flag.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
A HashTable similar to std::unordered_map.
Definition: HashTable.H:123
Input from file stream, using an ISstream.
Definition: IFstream.H:57
bool good() const noexcept
True if next operation might succeed.
Definition: IOstream.H:233
Generic input stream using a standard (STL) stream.
Definition: ISstream.H:58
virtual const fileName & name() const
Return the name of the stream.
Definition: ISstream.H:113
ISstream & getLine(std::string &str, char delim='\n')
Raw, low-level getline (until delimiter) into a string.
Definition: ISstreamI.H:76
virtual Ostream & writeQuoted(const std::string &str, const bool quoted=true)
Write std::string surrounded by quotes.
Definition: OBJstream.C:108
Output to file stream, using an OSstream.
Definition: OFstream.H:57
virtual const fileName & name() const
Read/write access to the name of the stream.
Definition: OSstream.H:107
Generic output stream using a standard (STL) stream.
Definition: OSstream.H:57
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
The SHA1 message digest.
Definition: SHA1Digest.H:61
Ostream & write(Ostream &os, const bool prefixed=false) const
Write (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1Digest.C:186
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1I.H:121
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition: Tuple2.H:58
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: UList.H:94
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:427
Extract command arguments and options from the supplied argc and argv parameters.
Definition: argList.H:124
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
static word fullname(word libName)
Library fullname, prefix with 'lib', suffix with '.so'.
Encapsulation of dynamic code dictionaries.
const string & code() const noexcept
The code.
const string & include() const noexcept
The code includes.
const SHA1 & sha1() const noexcept
The SHA1 calculated from options, libs, include, code, etc.
const string & localCode() const noexcept
The local (file-scope) code.
Tools for handling dynamic code compilation.
Definition: dynamicCode.H:60
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:166
static void copyAndFilter(ISstream &, OSstream &, const HashTable< string > &mapping)
Copy lines while expanding variables.
Definition: dynamicCode.C:102
bool copyOrCreateFiles(const bool verbose=false) const
Copy/create files prior to compilation.
Definition: dynamicCode.C:403
void addCopyFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:359
static const char *const targetLibDir
Directory for library targets for Make/files.
Definition: dynamicCode.H:111
fileName libRelPath() const
Library path for specified code name relative to <case>
Definition: dynamicCode.C:321
void addCreateFile(const fileName &name, const string &contents)
Add a file to create with its contents. Will not be filtered.
Definition: dynamicCode.C:366
static bool resolveTemplates(const UList< fileName > &templateNames, DynamicList< fileName > &resolvedFiles, DynamicList< fileName > &badFiles)
Resolve code-templates via the codeTemplateEnvName.
Definition: dynamicCode.C:139
static const word codeTemplateEnvName
Name of the code template environment variable.
Definition: dynamicCode.H:159
static const char *const topDirName
Top-level directory name for copy/compiling.
Definition: dynamicCode.H:114
void setFilterVariable(const word &key, const std::string &value)
Define a filter variable.
Definition: dynamicCode.C:388
void setFilterContext(const dynamicCodeContext &)
Define filter variables for code, codeInclude, SHA1sum.
Definition: dynamicCode.C:376
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:65
bool createMakeFiles() const
Copy/create Make/files prior to compilation.
Definition: dynamicCode.C:197
bool writeDigest(const SHA1Digest &) const
Write digest to Make/SHA1Digest.
Definition: dynamicCode.C:264
fileName codeRelPath() const
Path for specified code name relative to <case>
Definition: dynamicCode.C:309
void addCompileFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:353
void clear()
Clear files and variables.
Definition: dynamicCode.C:327
fileName libPath() const
Library path for specified code name.
Definition: dynamicCode.C:315
static const fileName codeTemplateDirName
Name of the code template sub-directory.
Definition: dynamicCode.H:163
bool createMakeOptions() const
Copy/create Make/options prior to compilation.
Definition: dynamicCode.C:235
bool wmakeLibso() const
Compile a libso.
Definition: dynamicCode.C:495
bool writeCommentSHA1(Ostream &) const
Write SHA1 value as C-comment.
Definition: dynamicCode.C:182
void setMakeOptions(const std::string &content)
Define contents for Make/options.
Definition: dynamicCode.C:397
void reset()
Reset to defaults.
A class for handling file names.
Definition: fileName.H:76
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:176
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:199
A line primitive.
Definition: line.H:68
A class for handling words, derived from Foam::string.
Definition: word.H:68
patchWriters clear()
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Functions to search 'etc' directories for configuration files etc.
#define DetailInfo
Definition: evalEntry.C:37
OBJstream os(runTime.globalPath()/outputName)
int infoSwitch(const char *name, const int deflt=0)
Lookup info switch or add default value.
Definition: debug.C:231
void inplaceExpand(std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:731
string expand(const std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:718
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: MSwindows.C:371
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:633
int system(const std::string &command, const bool bg=false)
Execute the specified command via the shell.
Definition: MSwindows.C:1158
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:515
bool isAdministrator()
Is the current user the administrator (root)
Definition: MSwindows.C:450
messageStream Info
Information stream (stdout output on master, null elsewhere)
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
OSstream Serr
OSstream wrapped stderr (std::cerr)
IOerror FatalIOError
int infoDetailLevel
Global for selective suppression of Info output.
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:666
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: MSwindows.C:651
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
dictionary dict