mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: new encapsulation: dynamicCode, dynamicCodeContext
- improve loading/unloading characteristics for codedFixedValue but still needs work
This commit is contained in:
@ -189,8 +189,9 @@ db/objectRegistry/objectRegistry.C
|
||||
db/CallbackRegistry/CallbackRegistryName.C
|
||||
|
||||
dll = db/dynamicLibrary
|
||||
$(dll)/codeStream/codeStreamTools.C
|
||||
$(dll)/dlLibraryTable/dlLibraryTable.C
|
||||
$(dll)/dynamicCode/dynamicCode.C
|
||||
$(dll)/dynamicCode/dynamicCodeContext.C
|
||||
|
||||
db/functionObjects/functionObject/functionObject.C
|
||||
db/functionObjects/functionObjectList/functionObjectList.C
|
||||
|
||||
@ -28,10 +28,9 @@ License
|
||||
#include "IStringStream.H"
|
||||
#include "OStringStream.H"
|
||||
#include "IOstreams.H"
|
||||
#include "SHA1Digest.H"
|
||||
#include "OSHA1stream.H"
|
||||
#include "codeStreamTools.H"
|
||||
#include "stringOps.H"
|
||||
#include "dynamicCode.H"
|
||||
#include "dynamicCodeContext.H"
|
||||
#include "dlLibraryTable.H"
|
||||
#include "OSspecific.H"
|
||||
#include "Time.H"
|
||||
@ -71,7 +70,7 @@ bool Foam::functionEntries::codeStream::execute
|
||||
Istream& is
|
||||
)
|
||||
{
|
||||
codeStreamTools::checkSecurity
|
||||
dynamicCode::checkSecurity
|
||||
(
|
||||
"functionEntries::codeStream::execute(..)",
|
||||
parentDict
|
||||
@ -81,54 +80,23 @@ bool Foam::functionEntries::codeStream::execute
|
||||
// must reference parent for stringOps::expand to work nicely
|
||||
dictionary codeDict("#codeStream", parentDict, is);
|
||||
|
||||
// get code, codeInclude, codeOptions
|
||||
dynamicCodeContext context(codeDict);
|
||||
|
||||
// Read three sections of code.
|
||||
// Remove any leading whitespace - necessary for compilation options,
|
||||
// convenience for includes and body.
|
||||
|
||||
// "codeInclude" is optional
|
||||
string codeInclude;
|
||||
if (codeDict.found("codeInclude"))
|
||||
{
|
||||
codeInclude = stringOps::trim(codeDict["codeInclude"]);
|
||||
stringOps::inplaceExpand(codeInclude, codeDict);
|
||||
}
|
||||
|
||||
// "codeOptions" is optional
|
||||
string codeOptions;
|
||||
if (codeDict.found("codeOptions"))
|
||||
{
|
||||
codeOptions = stringOps::trim(codeDict["codeOptions"]);
|
||||
stringOps::inplaceExpand(codeOptions, codeDict);
|
||||
}
|
||||
|
||||
// "code" is mandatory
|
||||
string code = stringOps::trim(codeDict["code"]);
|
||||
stringOps::inplaceExpand(code, codeDict);
|
||||
|
||||
|
||||
// Create SHA1 digest from the contents
|
||||
SHA1Digest sha;
|
||||
{
|
||||
OSHA1stream os;
|
||||
os << codeInclude << codeOptions << code;
|
||||
sha = os.digest();
|
||||
}
|
||||
|
||||
|
||||
// codeName = prefix + sha1
|
||||
const fileName codeName = "codeStream_" + sha.str();
|
||||
|
||||
// write code into _SHA1 subdir
|
||||
const fileName codePath = codeStreamTools::codePath("_" + sha.str());
|
||||
|
||||
// write library into platforms/$WM_OPTIONS/lib subdir
|
||||
const fileName libPath = codeStreamTools::libPath(codeName);
|
||||
// codeName: prefix_ + sha1
|
||||
// codeDir : _<sha1>
|
||||
dynamicCode dynCode
|
||||
(
|
||||
"codeStream_" + context.sha1().str(),
|
||||
"_" + context.sha1().str()
|
||||
);
|
||||
|
||||
// Load library if not already loaded
|
||||
// Version information is encoded in the libPath (encoded with the SHA1)
|
||||
const fileName libPath = dynCode.libPath();
|
||||
|
||||
void* lib = dlLibraryTable::findLibrary(libPath);
|
||||
|
||||
// try to load if not already loaded
|
||||
if (!lib && dlLibraryTable::open(libPath, false))
|
||||
{
|
||||
lib = dlLibraryTable::findLibrary(libPath);
|
||||
@ -139,76 +107,54 @@ bool Foam::functionEntries::codeStream::execute
|
||||
{
|
||||
if (Pstream::master())
|
||||
{
|
||||
if (!codeStreamTools::upToDate(codePath, sha))
|
||||
if (!dynCode.upToDate(context))
|
||||
{
|
||||
Info<< "Creating new library in " << libPath << endl;
|
||||
Info<< "Creating new library in "
|
||||
<< dynCode.libPath() << endl;
|
||||
|
||||
const fileName fileCsrc
|
||||
(
|
||||
codeStreamTools::findTemplate
|
||||
(
|
||||
codeTemplateC
|
||||
)
|
||||
);
|
||||
// filter C template
|
||||
dynCode.addFilterFile(codeTemplateC);
|
||||
|
||||
// not found!
|
||||
if (fileCsrc.empty())
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
"functionEntries::codeStream::execute(..)",
|
||||
parentDict
|
||||
) << "Could not find the code template: "
|
||||
<< codeTemplateC << nl
|
||||
<< codeStreamTools::searchedLocations()
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
|
||||
List<codeStreamTools::fileAndVars> copyFiles(1);
|
||||
copyFiles[0].file() = fileCsrc;
|
||||
copyFiles[0].set("codeInclude", codeInclude);
|
||||
copyFiles[0].set("code", code);
|
||||
copyFiles[0].set("SHA1sum", sha.str());
|
||||
|
||||
List<codeStreamTools::fileAndContent> filesContents(2);
|
||||
// filter with this context
|
||||
dynCode.setFilterContext(context);
|
||||
|
||||
// Write Make/files
|
||||
filesContents[0].first() = "Make/files";
|
||||
filesContents[0].second() =
|
||||
dynCode.addCreateFile
|
||||
(
|
||||
"Make/files",
|
||||
codeTemplateC + "\n\n"
|
||||
+ codeStreamTools::libTarget(codeName);
|
||||
+ dynCode.libTarget()
|
||||
);
|
||||
|
||||
// Write Make/options
|
||||
filesContents[1].first() = "Make/options";
|
||||
filesContents[1].second() =
|
||||
dynCode.addCreateFile
|
||||
(
|
||||
"Make/options",
|
||||
"EXE_INC = -g \\\n"
|
||||
+ codeOptions
|
||||
+ "\n\nLIB_LIBS =";
|
||||
+ context.options()
|
||||
+ "\n\nLIB_LIBS ="
|
||||
);
|
||||
|
||||
codeStreamTools writer(codeName, copyFiles, filesContents);
|
||||
if (!writer.copyFilesContents(codePath))
|
||||
if (!dynCode.copyFilesContents())
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
"functionEntries::codeStream::execute(..)",
|
||||
parentDict
|
||||
) << "Failed writing " <<nl
|
||||
<< copyFiles << endl
|
||||
<< filesContents
|
||||
) << "Failed writing " << nl
|
||||
// << copyFiles << endl
|
||||
// << filesContents
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
}
|
||||
|
||||
const Foam::string wmakeCmd("wmake libso " + codePath);
|
||||
Info<< "Invoking " << wmakeCmd << endl;
|
||||
if (Foam::system(wmakeCmd))
|
||||
if (!dynCode.wmakeLibso())
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
"functionEntries::codeStream::execute(..)",
|
||||
parentDict
|
||||
) << "Failed " << wmakeCmd
|
||||
) << "Failed wmake " << libPath
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
}
|
||||
@ -239,16 +185,17 @@ bool Foam::functionEntries::codeStream::execute
|
||||
void (*function)(const dictionary&, Ostream&);
|
||||
function = reinterpret_cast<void(*)(const dictionary&, Ostream&)>
|
||||
(
|
||||
dlSym(lib, codeName)
|
||||
dlSym(lib, dynCode.codeName())
|
||||
);
|
||||
|
||||
|
||||
if (!function)
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
"functionEntries::codeStream::execute(..)",
|
||||
parentDict
|
||||
) << "Failed looking up symbol " << codeName
|
||||
) << "Failed looking up symbol " << dynCode.codeName()
|
||||
<< " in library " << lib << exit(FatalIOError);
|
||||
}
|
||||
|
||||
|
||||
@ -1,369 +0,0 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2011 OpenCFD Ltd.
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "codeStreamTools.H"
|
||||
#include "stringOps.H"
|
||||
#include "IFstream.H"
|
||||
#include "OFstream.H"
|
||||
#include "OSspecific.H"
|
||||
#include "dictionary.H"
|
||||
#include "dlLibraryTable.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
int Foam::codeStreamTools::allowSystemOperations
|
||||
(
|
||||
Foam::debug::infoSwitch("allowSystemOperations", 0)
|
||||
);
|
||||
|
||||
|
||||
const Foam::word Foam::codeStreamTools::codeTemplateEnvName
|
||||
= "FOAM_CODE_TEMPLATES";
|
||||
|
||||
const Foam::fileName Foam::codeStreamTools::codeTemplateDirName
|
||||
= "codeTemplates/dynamicCode";
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
void Foam::codeStreamTools::checkSecurity
|
||||
(
|
||||
const char* title,
|
||||
const dictionary& context
|
||||
)
|
||||
{
|
||||
if (isAdministrator())
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
title,
|
||||
context
|
||||
) << "This code should not be executed by someone with administrator"
|
||||
<< " rights due to security reasons." << nl
|
||||
<< "(it writes a shared library which then gets loaded "
|
||||
<< "using dlopen)"
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Foam::fileName Foam::codeStreamTools::codePath(const word& subDirName)
|
||||
{
|
||||
return stringOps::expand("$FOAM_CASE/dynamicCode/" + subDirName);
|
||||
}
|
||||
|
||||
|
||||
Foam::fileName Foam::codeStreamTools::libPath(const word& codeName)
|
||||
{
|
||||
return stringOps::expand
|
||||
(
|
||||
"$FOAM_CASE/dynamicCode/platforms/$WM_OPTIONS/lib/lib"
|
||||
+ codeName + ".so"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Foam::string Foam::codeStreamTools::libTarget(const word& codeName)
|
||||
{
|
||||
return "LIB = $(PWD)/../platforms/$(WM_OPTIONS)/lib/lib" + codeName;
|
||||
}
|
||||
|
||||
|
||||
Foam::fileName Foam::codeStreamTools::findTemplate(const word& templateFile)
|
||||
{
|
||||
// try to get template from FOAM_CODE_TEMPLATES
|
||||
fileName templateDir(Foam::getEnv(codeTemplateEnvName));
|
||||
|
||||
fileName file;
|
||||
if (!templateDir.empty() && isDir(templateDir))
|
||||
{
|
||||
file = templateDir/templateFile;
|
||||
if (!isFile(file, false))
|
||||
{
|
||||
file.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// not found - fallback to ~OpenFOAM expansion
|
||||
if (file.empty())
|
||||
{
|
||||
file = findEtcFile(codeTemplateDirName/templateFile);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
Foam::string Foam::codeStreamTools::searchedLocations()
|
||||
{
|
||||
return
|
||||
(
|
||||
"Under the $"
|
||||
+ codeTemplateDirName
|
||||
+ " directory or via via the ~OpenFOAM/"
|
||||
+ codeTemplateDirName
|
||||
+ " expansion"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
void Foam::codeStreamTools::copyAndExpand
|
||||
(
|
||||
ISstream& is,
|
||||
OSstream& os,
|
||||
const HashTable<string>& mapping
|
||||
) const
|
||||
{
|
||||
if (!is.good())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"codeStreamTools::copyAndExpand()"
|
||||
" const"
|
||||
) << "Failed opening for reading " << is.name()
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
if (!os.good())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"codeStreamTools::copyAndExpand()"
|
||||
" const"
|
||||
) << "Failed writing " << os.name()
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// Copy file while rewriting $VARS and ${VARS}
|
||||
string line;
|
||||
do
|
||||
{
|
||||
is.getLine(line);
|
||||
|
||||
// expand according to mapping
|
||||
// expanding according to env variables might cause too many
|
||||
// surprises
|
||||
stringOps::inplaceExpand(line, mapping);
|
||||
|
||||
os << line.c_str() << nl;
|
||||
}
|
||||
while (is.good());
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::codeStreamTools::codeStreamTools()
|
||||
{}
|
||||
|
||||
|
||||
Foam::codeStreamTools::codeStreamTools
|
||||
(
|
||||
const word& name,
|
||||
const dictionary& dict
|
||||
)
|
||||
:
|
||||
name_(name)
|
||||
{
|
||||
read(dict);
|
||||
}
|
||||
|
||||
|
||||
Foam::codeStreamTools::codeStreamTools
|
||||
(
|
||||
const word& name,
|
||||
const List<fileAndVars>& copyFiles,
|
||||
const List<fileAndContent>& filesContents
|
||||
)
|
||||
:
|
||||
name_(name),
|
||||
copyFiles_(copyFiles),
|
||||
filesContents_(filesContents)
|
||||
{}
|
||||
|
||||
|
||||
Foam::codeStreamTools::codeStreamTools(const codeStreamTools& tools)
|
||||
:
|
||||
name_(tools.name_),
|
||||
copyFiles_(tools.copyFiles_),
|
||||
filesContents_(tools.filesContents_)
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::codeStreamTools::copyFilesContents(const fileName& dir) const
|
||||
{
|
||||
if (!allowSystemOperations)
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"codeStreamTools::copyFilesContents(const fileName&) const"
|
||||
) << "Loading a shared library using case-supplied code is not"
|
||||
<< " enabled by default" << nl
|
||||
<< "because of security issues. If you trust the code you can"
|
||||
<< " enable this" << nl
|
||||
<< "facility be adding to the InfoSwitches setting in the system"
|
||||
<< " controlDict:" << nl << nl
|
||||
<< " allowSystemOperations 1" << nl << nl
|
||||
<< "The system controlDict is either" << nl << nl
|
||||
<< " ~/.OpenFOAM/$WM_PROJECT_VERSION/controlDict" << nl << nl
|
||||
<< "or" << nl << nl
|
||||
<< " $WM_PROJECT_DIR/etc/controlDict" << nl
|
||||
<< endl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// Create dir
|
||||
mkDir(dir);
|
||||
|
||||
// Info<< "set mapping typeName=" << name_ << endl;
|
||||
// Copy any template files
|
||||
forAll(copyFiles_, i)
|
||||
{
|
||||
const fileName sourceFile(fileName(copyFiles_[i].file()).expand());
|
||||
const fileName destFile(dir/sourceFile.name());
|
||||
|
||||
IFstream is(sourceFile);
|
||||
//Info<< "Reading from " << is.name() << endl;
|
||||
if (!is.good())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"codeStreamTools::copyFilesContents(const fileName&)"
|
||||
" const"
|
||||
) << "Failed opening " << sourceFile << exit(FatalError);
|
||||
}
|
||||
|
||||
OFstream os(destFile);
|
||||
//Info<< "Writing to " << destFile.name() << endl;
|
||||
if (!os.good())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"codeStreamTools::copyFilesContents(const fileName&)"
|
||||
" const"
|
||||
) << "Failed writing " << destFile << exit(FatalError);
|
||||
}
|
||||
|
||||
// variables mapping
|
||||
HashTable<string> mapping(copyFiles_[i]);
|
||||
mapping.set("typeName", name_);
|
||||
|
||||
// provide a zero digest if not otherwise specified
|
||||
if (!mapping.found("SHA1sum"))
|
||||
{
|
||||
mapping.insert("SHA1sum", SHA1Digest().str());
|
||||
}
|
||||
|
||||
copyAndExpand(is, os, mapping);
|
||||
}
|
||||
|
||||
|
||||
// Files that are always written:
|
||||
forAll(filesContents_, i)
|
||||
{
|
||||
const fileName dstFile
|
||||
(
|
||||
fileName(dir/filesContents_[i].first()).expand()
|
||||
);
|
||||
|
||||
mkDir(dstFile.path());
|
||||
OFstream os(dstFile);
|
||||
//Info<< "Writing to " << filesContents_[i].first() << endl;
|
||||
if (!os.good())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"codeStreamTools::copyFilesContents()"
|
||||
" const"
|
||||
) << "Failed writing " << dstFile << exit(FatalError);
|
||||
}
|
||||
os << filesContents_[i].second().c_str() << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::codeStreamTools::writeDigest
|
||||
(
|
||||
const fileName& dir,
|
||||
const SHA1Digest& sha1
|
||||
)
|
||||
{
|
||||
OFstream os(dir/"SHA1Digest");
|
||||
os << sha1;
|
||||
return os.good();
|
||||
}
|
||||
|
||||
|
||||
Foam::SHA1Digest Foam::codeStreamTools::readDigest(const fileName& dir)
|
||||
{
|
||||
IFstream is(dir/"SHA1Digest");
|
||||
return SHA1Digest(is);
|
||||
}
|
||||
|
||||
|
||||
bool Foam::codeStreamTools::upToDate
|
||||
(
|
||||
const fileName& dir,
|
||||
const SHA1Digest& sha1
|
||||
)
|
||||
{
|
||||
if (!exists(dir/"SHA1Digest") || readDigest(dir) != sha1)
|
||||
{
|
||||
writeDigest(dir, sha1);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Foam::codeStreamTools::read(const dictionary& dict)
|
||||
{
|
||||
dict.lookup("copyFiles") >> copyFiles_;
|
||||
dict.lookup("filesContents") >> filesContents_;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Foam::codeStreamTools::writeDict(Ostream& os) const
|
||||
{
|
||||
os.writeKeyword("copyFiles") << copyFiles_ << token::END_STATEMENT << nl;
|
||||
os.writeKeyword("filesContents") << filesContents_ << token::END_STATEMENT
|
||||
<< nl;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
479
src/OpenFOAM/db/dynamicLibrary/dynamicCode/dynamicCode.C
Normal file
479
src/OpenFOAM/db/dynamicLibrary/dynamicCode/dynamicCode.C
Normal file
@ -0,0 +1,479 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2011 OpenCFD Ltd.
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "dynamicCode.H"
|
||||
#include "dynamicCodeContext.H"
|
||||
#include "stringOps.H"
|
||||
#include "IFstream.H"
|
||||
#include "OFstream.H"
|
||||
#include "OSspecific.H"
|
||||
#include "dictionary.H"
|
||||
#include "dlLibraryTable.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
int Foam::dynamicCode::allowSystemOperations
|
||||
(
|
||||
Foam::debug::infoSwitch("allowSystemOperations", 0)
|
||||
);
|
||||
|
||||
|
||||
const Foam::word Foam::dynamicCode::codeTemplateEnvName
|
||||
= "FOAM_CODE_TEMPLATES";
|
||||
|
||||
const Foam::fileName Foam::dynamicCode::codeTemplateDirName
|
||||
= "codeTemplates/dynamicCode";
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
void Foam::dynamicCode::checkSecurity
|
||||
(
|
||||
const char* title,
|
||||
const dictionary& dict
|
||||
)
|
||||
{
|
||||
if (isAdministrator())
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
title,
|
||||
dict
|
||||
) << "This code should not be executed by someone with administrator"
|
||||
<< " rights due to security reasons." << nl
|
||||
<< "(it writes a shared library which then gets loaded "
|
||||
<< "using dlopen)"
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
||||
|
||||
void Foam::dynamicCode::copyAndFilter
|
||||
(
|
||||
ISstream& is,
|
||||
OSstream& os,
|
||||
const HashTable<string>& mapping
|
||||
) const
|
||||
{
|
||||
if (!is.good())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"dynamicCode::copyAndFilter()"
|
||||
" const"
|
||||
) << "Failed opening for reading " << is.name()
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
if (!os.good())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"dynamicCode::copyAndFilter()"
|
||||
" const"
|
||||
) << "Failed writing " << os.name()
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// Copy file while rewriting $VARS and ${VARS}
|
||||
string line;
|
||||
do
|
||||
{
|
||||
is.getLine(line);
|
||||
|
||||
// expand according to mapping
|
||||
// expanding according to env variables might cause too many
|
||||
// surprises
|
||||
stringOps::inplaceExpand(line, mapping);
|
||||
|
||||
os << line.c_str() << nl;
|
||||
}
|
||||
while (is.good());
|
||||
}
|
||||
|
||||
|
||||
Foam::List<Foam::fileName>
|
||||
Foam::dynamicCode::resolveTemplates(const UList<fileName>& names)
|
||||
{
|
||||
// try to get template from FOAM_CODESTREAM_TEMPLATES
|
||||
const fileName templateDir(Foam::getEnv(codeTemplateEnvName));
|
||||
|
||||
DynamicList<fileName> badFiles(names.size());
|
||||
List<fileName> resolved(names.size());
|
||||
|
||||
label nResolved = 0;
|
||||
|
||||
forAll(names, fileI)
|
||||
{
|
||||
const fileName& templateName = names[fileI];
|
||||
|
||||
fileName file;
|
||||
if (!templateDir.empty() && isDir(templateDir))
|
||||
{
|
||||
file = templateDir/templateName;
|
||||
if (!isFile(file, false))
|
||||
{
|
||||
file.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// not found - fallback to ~OpenFOAM expansion
|
||||
if (file.empty())
|
||||
{
|
||||
file = findEtcFile(codeTemplateDirName/templateName);
|
||||
}
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
badFiles.append(templateName);
|
||||
}
|
||||
else
|
||||
{
|
||||
resolved[nResolved++] = file;
|
||||
}
|
||||
}
|
||||
|
||||
resolved.setSize(nResolved);
|
||||
|
||||
if (!badFiles.empty())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"dynamicCode::resolveTemplates(..)"
|
||||
) << "Could not find the code template(s): "
|
||||
<< badFiles << nl
|
||||
<< "Under the $" << codeTemplateDirName
|
||||
<< " directory or via via the ~OpenFOAM/"
|
||||
<< codeTemplateDirName << " expansion"
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::dynamicCode::dynamicCode(const word& codeName)
|
||||
:
|
||||
codeName_(codeName),
|
||||
codeDirName_(codeName)
|
||||
{
|
||||
filterVars_.set("typeName", codeName_);
|
||||
filterVars_.set("SHA1sum", SHA1Digest().str());
|
||||
}
|
||||
|
||||
Foam::dynamicCode::dynamicCode(const word& codeName, const word& codeDirName)
|
||||
:
|
||||
codeName_(codeName),
|
||||
codeDirName_(codeDirName)
|
||||
{
|
||||
filterVars_.set("typeName", codeName_);
|
||||
filterVars_.set("SHA1sum", SHA1Digest().str());
|
||||
}
|
||||
|
||||
|
||||
// Foam::dynamicCode::dynamicCode(const dynamicCode& dc)
|
||||
// :
|
||||
// codeName_(dc.codeName_),
|
||||
// copyFiles_(dc.copyFiles_),
|
||||
// filesContents_(dc.filesContents_)
|
||||
// {}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::dynamicCode::clear()
|
||||
{
|
||||
filterVars_.clear();
|
||||
filterFiles_.clear();
|
||||
createFiles_.clear();
|
||||
filterVars_.set("typeName", codeName_);
|
||||
filterVars_.set("SHA1sum", SHA1Digest().str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Foam::dynamicCode::addCreateFile
|
||||
(
|
||||
const fileName& name,
|
||||
const string& contents
|
||||
)
|
||||
{
|
||||
createFiles_.append(fileAndContent(name, contents));
|
||||
}
|
||||
|
||||
|
||||
void Foam::dynamicCode::addFilterFile
|
||||
(
|
||||
const fileName& name
|
||||
)
|
||||
{
|
||||
filterFiles_.append(name);
|
||||
}
|
||||
|
||||
|
||||
void Foam::dynamicCode::setFilterContext
|
||||
(
|
||||
const dynamicCodeContext& context
|
||||
)
|
||||
{
|
||||
filterVars_.set("code", context.code());
|
||||
filterVars_.set("codeInclude", context.include());
|
||||
filterVars_.set("SHA1sum", context.sha1().str());
|
||||
}
|
||||
|
||||
|
||||
void Foam::dynamicCode::setFilterVariable
|
||||
(
|
||||
const word& key,
|
||||
const string& value
|
||||
)
|
||||
{
|
||||
filterVars_.set(key, value);
|
||||
}
|
||||
|
||||
|
||||
Foam::fileName Foam::dynamicCode::codePath() const
|
||||
{
|
||||
return stringOps::expand("$FOAM_CASE/dynamicCode/" + codeDirName_);
|
||||
}
|
||||
|
||||
|
||||
Foam::fileName Foam::dynamicCode::libPath() const
|
||||
{
|
||||
return
|
||||
(
|
||||
stringOps::expand
|
||||
(
|
||||
"$FOAM_CASE/dynamicCode/platforms/$WM_OPTIONS/lib/lib"
|
||||
)
|
||||
+ codeName_ + ".so"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Foam::string Foam::dynamicCode::libTarget() const
|
||||
{
|
||||
return "LIB = $(PWD)/../platforms/$(WM_OPTIONS)/lib/lib" + codeName_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Foam::dynamicCode::copyFilesContents() const
|
||||
{
|
||||
if (!allowSystemOperations)
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"dynamicCode::copyFilesContents(const fileName&) const"
|
||||
) << "Loading a shared library using case-supplied code is not"
|
||||
<< " enabled by default" << nl
|
||||
<< "because of security issues. If you trust the code you can"
|
||||
<< " enable this" << nl
|
||||
<< "facility be adding to the InfoSwitches setting in the system"
|
||||
<< " controlDict:" << nl << nl
|
||||
<< " allowSystemOperations 1" << nl << nl
|
||||
<< "The system controlDict is either" << nl << nl
|
||||
<< " ~/.OpenFOAM/$WM_PROJECT_VERSION/controlDict" << nl << nl
|
||||
<< "or" << nl << nl
|
||||
<< " $WM_PROJECT_DIR/etc/controlDict" << nl
|
||||
<< endl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
List<fileName> resolvedFiles = resolveTemplates(filterFiles_);
|
||||
|
||||
// Create dir
|
||||
const fileName outputDir = this->codePath();
|
||||
|
||||
// Create dir
|
||||
mkDir(outputDir);
|
||||
|
||||
// Copy/filter files
|
||||
forAll(resolvedFiles, fileI)
|
||||
{
|
||||
const fileName& srcFile = resolvedFiles[fileI];
|
||||
const fileName dstFile(outputDir/srcFile.name());
|
||||
|
||||
IFstream is(srcFile);
|
||||
//Info<< "Reading from " << is.name() << endl;
|
||||
if (!is.good())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"dynamicCode::copyFilesContents(const fileName&)"
|
||||
" const"
|
||||
) << "Failed opening " << srcFile
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
OFstream os(dstFile);
|
||||
//Info<< "Writing to " << dstFile.name() << endl;
|
||||
if (!os.good())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"dynamicCode::copyFilesContents(const fileName&)"
|
||||
" const"
|
||||
) << "Failed writing " << dstFile
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// variables mapping
|
||||
copyAndFilter(is, os, filterVars_);
|
||||
}
|
||||
|
||||
|
||||
// Create files:
|
||||
forAll(createFiles_, fileI)
|
||||
{
|
||||
const fileName dstFile
|
||||
(
|
||||
outputDir/stringOps::expand(createFiles_[fileI].first())
|
||||
);
|
||||
|
||||
mkDir(dstFile.path());
|
||||
OFstream os(dstFile);
|
||||
//Info<< "Writing to " << createFiles_[fileI].first() << endl;
|
||||
if (!os.good())
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
"dynamicCode::copyFilesContents()"
|
||||
" const"
|
||||
) << "Failed writing " << dstFile
|
||||
<< exit(FatalError);
|
||||
}
|
||||
os << createFiles_[fileI].second().c_str() << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::dynamicCode::wmakeLibso() const
|
||||
{
|
||||
const Foam::string wmakeCmd("wmake libso " + this->codePath());
|
||||
Info<< "Invoking " << wmakeCmd << endl;
|
||||
|
||||
if (Foam::system(wmakeCmd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Foam::dynamicCode::writeDigest
|
||||
(
|
||||
const fileName& dirName,
|
||||
const SHA1Digest& sha1
|
||||
) const
|
||||
{
|
||||
mkDir(dirName);
|
||||
OFstream os(dirName/"SHA1Digest");
|
||||
os << sha1;
|
||||
return os.good();
|
||||
}
|
||||
|
||||
|
||||
Foam::SHA1Digest Foam::dynamicCode::readDigest(const fileName& dirName) const
|
||||
{
|
||||
IFstream is(dirName/"SHA1Digest");
|
||||
return SHA1Digest(is);
|
||||
}
|
||||
|
||||
|
||||
bool Foam::dynamicCode::upToDate(const SHA1Digest& sha1) const
|
||||
{
|
||||
const fileName dirName = this->codePath();
|
||||
if (!exists(dirName/"SHA1Digest") || readDigest(dirName) != sha1)
|
||||
{
|
||||
writeDigest(dirName, sha1);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Foam::dynamicCode::upToDate(const dynamicCodeContext& context) const
|
||||
{
|
||||
return upToDate(context.sha1());
|
||||
}
|
||||
|
||||
|
||||
// bool Foam::dynamicCode::openLibrary() const
|
||||
// {
|
||||
// return dlLibraryTable::openLibrary(this->libPath(), false);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// bool Foam::dynamicCode::closeLibrary() const
|
||||
// {
|
||||
// return dlLibraryTable::closeLibrary(this->libPath(), false);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// void* Foam::dynamicCode::findLibrary() const
|
||||
// {
|
||||
// return dlLibraryTable::findLibrary(this->libPath());
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// bool Foam::dynamicCode::read(const dictionary& dict)
|
||||
// {
|
||||
// dict.lookup("createFiles") >> createFiles_;
|
||||
// dict.lookup("filterFiles") >> filterFiles_;
|
||||
// dict.lookup("filterVariables") >> filterVariables_;
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// void Foam::dynamicCode::writeDict(Ostream& os) const
|
||||
// {
|
||||
// os.writeKeyword("createFiles") << createFiles_
|
||||
// << token::END_STATEMENT << nl;
|
||||
//
|
||||
// os.writeKeyword("filterFiles") << filterFiles_
|
||||
// << token::END_STATEMENT << nl;
|
||||
//
|
||||
// os.writeKeyword("filterVariables") << filterVariables_
|
||||
// << token::END_STATEMENT << nl;
|
||||
// }
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -23,23 +23,24 @@ License
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Class
|
||||
Foam::codeStreamTools
|
||||
Foam::dynamicCode
|
||||
|
||||
Description
|
||||
Base for all things on-the-fly from dictionary
|
||||
Tools for handling dynamic code compilation
|
||||
|
||||
SourceFiles
|
||||
codeStreamTools.C
|
||||
dynamicCode.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef codeStreamTools_H
|
||||
#define codeStreamTools_H
|
||||
#ifndef dynamicCode_H
|
||||
#define dynamicCode_H
|
||||
|
||||
#include "Tuple2.H"
|
||||
#include "Pair.H"
|
||||
#include "SHA1Digest.H"
|
||||
#include "HashTable.H"
|
||||
#include "DynamicList.H"
|
||||
#include "dlLibraryTable.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -47,66 +48,58 @@ namespace Foam
|
||||
{
|
||||
|
||||
// Forward declaration of classes
|
||||
class dynamicCodeContext;
|
||||
class ISstream;
|
||||
class OSstream;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class codeStreamTools Declaration
|
||||
Class dynamicCode Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class codeStreamTools
|
||||
class dynamicCode
|
||||
{
|
||||
public:
|
||||
typedef Tuple2<fileName, string> fileAndContent;
|
||||
|
||||
//- Helper class for managing file and variables
|
||||
class fileAndVars
|
||||
:
|
||||
public HashTable<string>
|
||||
{
|
||||
// Private data
|
||||
fileName file_;
|
||||
|
||||
public:
|
||||
//- Construct null
|
||||
fileAndVars()
|
||||
{}
|
||||
|
||||
//- Return the file name
|
||||
const fileName& file() const
|
||||
{
|
||||
return file_;
|
||||
}
|
||||
|
||||
//- Return the file name
|
||||
fileName& file()
|
||||
{
|
||||
return file_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
// Private data
|
||||
|
||||
//- Name for underlying set
|
||||
word name_;
|
||||
//- Name for code
|
||||
word codeName_;
|
||||
|
||||
//- Files to copy
|
||||
List<codeStreamTools::fileAndVars> copyFiles_;
|
||||
//- Name for code subdirectory
|
||||
mutable word codeDirName_;
|
||||
|
||||
//- Variables to use during filtering
|
||||
HashTable<string> filterVars_;
|
||||
|
||||
//- Direct contents for files
|
||||
List<fileAndContent> filesContents_;
|
||||
DynamicList<fileAndContent> createFiles_;
|
||||
|
||||
//- Files to copy and filter
|
||||
DynamicList<fileName> filterFiles_;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void copyAndExpand
|
||||
void copyAndFilter
|
||||
(
|
||||
ISstream&,
|
||||
OSstream&,
|
||||
const HashTable<string>& mapping
|
||||
) const;
|
||||
|
||||
//- Resolve code-templates via the codeTemplateEnvName
|
||||
// alternatively in the codeTemplateDirName via Foam::findEtcFile
|
||||
static List<fileName> resolveTemplates
|
||||
(
|
||||
const UList<fileName>& names
|
||||
);
|
||||
|
||||
|
||||
bool writeDigest(const fileName& dir, const SHA1Digest& sha1) const;
|
||||
SHA1Digest readDigest(const fileName& dir) const;
|
||||
|
||||
public:
|
||||
|
||||
// Static data members
|
||||
@ -119,87 +112,94 @@ public:
|
||||
// Used when locating the codeTemplateName via Foam::findEtcFile
|
||||
static const fileName codeTemplateDirName;
|
||||
|
||||
|
||||
static int allowSystemOperations;
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct null
|
||||
codeStreamTools();
|
||||
|
||||
//- Construct from dictionary
|
||||
codeStreamTools(const word& name, const dictionary& dict);
|
||||
|
||||
//- Copy from components
|
||||
codeStreamTools
|
||||
(
|
||||
const word& name,
|
||||
const List<fileAndVars>&,
|
||||
const List<fileAndContent>&
|
||||
);
|
||||
|
||||
//- Construct copy
|
||||
codeStreamTools(const codeStreamTools&);
|
||||
|
||||
|
||||
// Member functions
|
||||
// Static Member functions
|
||||
|
||||
//- Check security for creating dynamic code
|
||||
static void checkSecurity
|
||||
(
|
||||
const char* title,
|
||||
const dictionary& context
|
||||
const dictionary& dict
|
||||
);
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct for a specified code name
|
||||
dynamicCode(const word& codeName);
|
||||
|
||||
//- Construct for a specified code name and directory name
|
||||
dynamicCode(const word& codeName, const word& dirName);
|
||||
|
||||
|
||||
// Member functions
|
||||
|
||||
//- Return the code-name
|
||||
const word& codeName() const
|
||||
{
|
||||
return codeName_;
|
||||
}
|
||||
|
||||
//- Return the code-dirname
|
||||
const word& codeDirName() const
|
||||
{
|
||||
return codeDirName_;
|
||||
}
|
||||
|
||||
//- Clear variables and files
|
||||
void clear();
|
||||
|
||||
|
||||
//- Add a file to create with its contents. Will not be filtered
|
||||
void addCreateFile(const fileName& name, const string& contents);
|
||||
|
||||
//- Add a file template name, which will be found and filtered
|
||||
void addFilterFile(const fileName& name);
|
||||
|
||||
//- Define filter variables for code, codeInclude, SHA1sum
|
||||
void setFilterContext(const dynamicCodeContext&);
|
||||
|
||||
//- Define a filter variable
|
||||
void setFilterVariable(const word& key, const string& value);
|
||||
|
||||
|
||||
//- Local path for specified code name
|
||||
// Expanded from \$FOAM_CASE/codeStream
|
||||
static fileName codePath(const word& subDirName);
|
||||
// Expanded from \$FOAM_CASE/dynamicCode/codeDirName
|
||||
fileName codePath() const;
|
||||
|
||||
//- Local library path for specified code name
|
||||
// Expanded from \$FOAM_CASE/platforms/\$WM_OPTIONS/lib
|
||||
static fileName libPath(const word& codeName);
|
||||
// Expanded from \$FOAM_CASE/dynamicCode/platforms/\$WM_OPTIONS/lib
|
||||
fileName libPath() const;
|
||||
|
||||
//- The library target path for Make/files
|
||||
static string libTarget(const word& codeName);
|
||||
string libTarget() const;
|
||||
|
||||
|
||||
//- Find a code-template via the codeTemplateEnvName
|
||||
// alternatively in the codeTemplateDirName via Foam::findEtcFile
|
||||
static fileName findTemplate(const word& templateName);
|
||||
//- Verify if the copied code is up-to-date
|
||||
bool upToDate(const dynamicCodeContext& context) const;
|
||||
|
||||
//- List searched locations in a format suitable for display an error
|
||||
static string searchedLocations();
|
||||
//- Verify if the copied code is up-to-date
|
||||
bool upToDate(const SHA1Digest& sha1) const;
|
||||
|
||||
//- Copy/create files prior to compilation
|
||||
bool copyFilesContents() const;
|
||||
|
||||
//- Compile a libso
|
||||
bool wmakeLibso() const;
|
||||
|
||||
const word& name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
// //- Open the libPath() library
|
||||
// bool openLibrary() const;
|
||||
//
|
||||
// //- Close the libPath() library
|
||||
// bool closeLibrary() const;
|
||||
//
|
||||
// //- Find the handle of the libPath() library
|
||||
// void* findLibrary() const;
|
||||
|
||||
const List<fileAndVars>& copyFiles() const
|
||||
{
|
||||
return copyFiles_;
|
||||
}
|
||||
|
||||
const List<Tuple2<fileName, string> >& filesContents() const
|
||||
{
|
||||
return filesContents_;
|
||||
}
|
||||
|
||||
bool copyFilesContents(const fileName& dir) const;
|
||||
|
||||
|
||||
static void* findLibrary(const fileName& libPath);
|
||||
|
||||
static bool writeDigest(const fileName& dir, const SHA1Digest& sha1);
|
||||
static SHA1Digest readDigest(const fileName& dir);
|
||||
static bool upToDate(const fileName& dir, const SHA1Digest& sha1);
|
||||
|
||||
bool read(const dictionary&);
|
||||
|
||||
void writeDict(Ostream&) const;
|
||||
// bool read(const dictionary&);
|
||||
// void writeDict(Ostream&) const;
|
||||
|
||||
};
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2011 OpenCFD Ltd.
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "dynamicCodeContext.H"
|
||||
#include "stringOps.H"
|
||||
#include "OSHA1stream.H"
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::dynamicCodeContext::dynamicCodeContext(const dictionary& dict)
|
||||
:
|
||||
dict_(dict),
|
||||
code_(stringOps::trim(dict["code"])),
|
||||
include_(),
|
||||
options_()
|
||||
{
|
||||
// expand dictionary entries
|
||||
stringOps::inplaceExpand(code_, dict);
|
||||
|
||||
// note: removes any leading/trailing whitespace
|
||||
// - necessary for compilation options, convenient for includes
|
||||
// and body.
|
||||
|
||||
// optional
|
||||
if (dict.found("codeInclude"))
|
||||
{
|
||||
include_ = stringOps::trim(dict["codeInclude"]);
|
||||
stringOps::inplaceExpand(include_, dict);
|
||||
}
|
||||
|
||||
// optional
|
||||
if (dict.found("codeOptions"))
|
||||
{
|
||||
options_ = stringOps::trim(dict["codeOptions"]);
|
||||
stringOps::inplaceExpand(options_, dict);
|
||||
}
|
||||
|
||||
// calculate SHA1 digest from include, options, code
|
||||
OSHA1stream os;
|
||||
os << include_ << options_ << code_;
|
||||
sha1_ = os.digest();
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
120
src/OpenFOAM/db/dynamicLibrary/dynamicCode/dynamicCodeContext.H
Normal file
120
src/OpenFOAM/db/dynamicLibrary/dynamicCode/dynamicCodeContext.H
Normal file
@ -0,0 +1,120 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2011-2011 OpenCFD Ltd.
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Class
|
||||
Foam::dynamicCodeContext
|
||||
|
||||
Description
|
||||
Encapsulation of dynamic code dictionaries
|
||||
|
||||
SourceFiles
|
||||
dynamicCodeContext.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef dynamicCodeContext_H
|
||||
#define dynamicCodeContext_H
|
||||
|
||||
#include "dictionary.H"
|
||||
#include "SHA1Digest.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class dynamicCodeContext Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class dynamicCodeContext
|
||||
{
|
||||
// Private data
|
||||
//- The parent dictionary context
|
||||
const dictionary& dict_;
|
||||
|
||||
//- Mandatory "code" entry
|
||||
string code_;
|
||||
|
||||
//- Optional "codeInclude" entry
|
||||
string include_;
|
||||
|
||||
//- Optional "codeOptions" entry
|
||||
string options_;
|
||||
|
||||
//- Calculated SHA1Digest
|
||||
SHA1Digest sha1_;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from a dictionary
|
||||
dynamicCodeContext(const dictionary&);
|
||||
|
||||
// Member functions
|
||||
|
||||
//- Return the parent dictionary context
|
||||
const dictionary& dict() const
|
||||
{
|
||||
return dict_;
|
||||
}
|
||||
|
||||
//- Return the code-includes
|
||||
const string& include() const
|
||||
{
|
||||
return include_;
|
||||
}
|
||||
|
||||
//- Return the code-options
|
||||
const string& options() const
|
||||
{
|
||||
return options_;
|
||||
}
|
||||
|
||||
//- Return the code
|
||||
const string& code() const
|
||||
{
|
||||
return code_;
|
||||
}
|
||||
|
||||
//- Return SHA1 digest calculated from include, options, code
|
||||
const SHA1Digest& sha1() const
|
||||
{
|
||||
return sha1_;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -32,7 +32,7 @@ License
|
||||
#include "JobInfo.H"
|
||||
#include "labelList.H"
|
||||
#include "regIOobject.H"
|
||||
#include "codeStreamTools.H"
|
||||
#include "dynamicCode.H"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
@ -790,7 +790,7 @@ Foam::argList::argList
|
||||
<< endl;
|
||||
|
||||
Info<< "allowSystemOperations : ";
|
||||
if (codeStreamTools::allowSystemOperations)
|
||||
if (dynamicCode::allowSystemOperations)
|
||||
{
|
||||
Info<< "Allowing user-supplied system call operations" << endl;
|
||||
}
|
||||
|
||||
@ -33,8 +33,8 @@ License
|
||||
#include "IFstream.H"
|
||||
#include "OFstream.H"
|
||||
#include "SHA1Digest.H"
|
||||
#include "OSHA1stream.H"
|
||||
#include "codeStreamTools.H"
|
||||
#include "dynamicCode.H"
|
||||
#include "dynamicCodeContext.H"
|
||||
#include "codeProperties.H"
|
||||
#include "stringOps.H"
|
||||
|
||||
@ -78,113 +78,52 @@ Foam::codedFixedValueFvPatchScalarField::dict() const
|
||||
}
|
||||
|
||||
|
||||
void Foam::codedFixedValueFvPatchScalarField::writeLibrary
|
||||
void Foam::codedFixedValueFvPatchScalarField::createLibrary
|
||||
(
|
||||
const fileName& codePath,
|
||||
const fileName& libPath,
|
||||
const dictionary& dict
|
||||
dynamicCode& dynCode,
|
||||
const dynamicCodeContext& context
|
||||
)
|
||||
{
|
||||
// Write files for new library
|
||||
if (!Pstream::master())
|
||||
if (Pstream::master() && !dynCode.upToDate(context))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Info<< "Creating new library in " << dynCode.libPath() << endl;
|
||||
dynCode.clear();
|
||||
|
||||
// "codeInclude" is optional
|
||||
string codeInclude;
|
||||
if (dict.found("codeInclude"))
|
||||
{
|
||||
codeInclude = stringOps::trim(dict["codeInclude"]);
|
||||
stringOps::inplaceExpand(codeInclude, dict);
|
||||
}
|
||||
// filter with this context
|
||||
dynCode.setFilterContext(context);
|
||||
|
||||
// "codeOptions" is optional
|
||||
string codeOptions;
|
||||
if (dict.found("codeOptions"))
|
||||
{
|
||||
codeOptions = stringOps::trim(dict["codeOptions"]);
|
||||
stringOps::inplaceExpand(codeOptions, dict);
|
||||
}
|
||||
// filter C/H template
|
||||
dynCode.addFilterFile(codeTemplateC);
|
||||
dynCode.addFilterFile(codeTemplateH);
|
||||
|
||||
// "code" is mandatory
|
||||
string code = stringOps::trim(dict["code"]);
|
||||
stringOps::inplaceExpand(code, dict);
|
||||
|
||||
|
||||
// Create SHA1 digest from the contents
|
||||
SHA1Digest sha;
|
||||
{
|
||||
OSHA1stream os;
|
||||
os << codeInclude << codeOptions << code;
|
||||
sha = os.digest();
|
||||
}
|
||||
|
||||
// Info<<"old SHA1: " << sha1_ << nl
|
||||
// <<"new SHA1: " << sha << endl;
|
||||
|
||||
|
||||
// only use side-effect of writing SHA1Digest for now
|
||||
(void) codeStreamTools::upToDate(codePath, sha);
|
||||
|
||||
// TODO: compile on-demand
|
||||
if (true)
|
||||
{
|
||||
Info<< "Creating new library in " << libPath << endl;
|
||||
|
||||
const fileName fileCsrc(codeStreamTools::findTemplate(codeTemplateC));
|
||||
const fileName fileHsrc(codeStreamTools::findTemplate(codeTemplateH));
|
||||
|
||||
// not found!
|
||||
if (fileCsrc.empty() || fileHsrc.empty())
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
"codedFixedValueFvPatchScalarField::writeLibrary(..)",
|
||||
dict
|
||||
) << "Could not find one or both code templates: "
|
||||
<< codeTemplateC << ", " << codeTemplateH << nl
|
||||
<< codeStreamTools::searchedLocations()
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
|
||||
|
||||
List<codeStreamTools::fileAndVars> copyFiles(2);
|
||||
copyFiles[0].file() = fileCsrc;
|
||||
copyFiles[0].set("codeInclude", codeInclude);
|
||||
copyFiles[0].set("code", code);
|
||||
copyFiles[0].set("SHA1sum", sha.str());
|
||||
|
||||
copyFiles[1].file() = fileHsrc;
|
||||
|
||||
|
||||
List<codeStreamTools::fileAndContent> filesContents(2);
|
||||
|
||||
// Write Make/files
|
||||
filesContents[0].first() = "Make/files";
|
||||
filesContents[0].second() =
|
||||
// Make/files
|
||||
dynCode.addCreateFile
|
||||
(
|
||||
"Make/files",
|
||||
codeTemplateC + "\n\n"
|
||||
+ codeStreamTools::libTarget(redirectType_);
|
||||
+ dynCode.libTarget()
|
||||
);
|
||||
|
||||
// Write Make/options
|
||||
filesContents[1].first() = "Make/options";
|
||||
filesContents[1].second() =
|
||||
// Make/options
|
||||
dynCode.addCreateFile
|
||||
(
|
||||
"Make/options",
|
||||
"EXE_INC = -g \\\n"
|
||||
"-I$(LIB_SRC)/finiteVolume/lnInclude\\\n"
|
||||
+ codeOptions
|
||||
+ "\n\nLIB_LIBS = ";
|
||||
+ context.options()
|
||||
+ "\n\nLIB_LIBS = "
|
||||
);
|
||||
|
||||
codeStreamTools writer(redirectType_, copyFiles, filesContents);
|
||||
if (!writer.copyFilesContents(codePath))
|
||||
if (!dynCode.copyFilesContents())
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
"codedFixedValueFvPatchScalarField::writeLibrary(..)",
|
||||
dict
|
||||
context.dict()
|
||||
) << "Failed writing " << nl
|
||||
<< copyFiles << nl
|
||||
<< filesContents
|
||||
// << copyFiles << nl
|
||||
// << filesContents
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
}
|
||||
@ -193,98 +132,113 @@ void Foam::codedFixedValueFvPatchScalarField::writeLibrary
|
||||
|
||||
void Foam::codedFixedValueFvPatchScalarField::updateLibrary()
|
||||
{
|
||||
codeStreamTools::checkSecurity
|
||||
dynamicCode::checkSecurity
|
||||
(
|
||||
"codedFixedValueFvPatchScalarField::updateLibrary()",
|
||||
dict_
|
||||
);
|
||||
|
||||
// write code into redirectType_ subdir
|
||||
const fileName codePath = codeStreamTools::codePath(redirectType_);
|
||||
// use in-line or via codeProperties
|
||||
const bool useInlineDict = dict_.found("code");
|
||||
|
||||
// const fileName oldLibPath = codeStreamTools::libPath
|
||||
// (
|
||||
// redirectType_ + "_" + sha1_
|
||||
// );
|
||||
|
||||
// write library into platforms/$WM_OPTIONS/lib subdir
|
||||
const fileName libPath = codeStreamTools::libPath(redirectType_);
|
||||
// determine code context (code, codeInclude, codeOptions)
|
||||
dynamicCodeContext context
|
||||
(
|
||||
useInlineDict
|
||||
? dict_
|
||||
: this->dict().subDict(redirectType_)
|
||||
);
|
||||
|
||||
|
||||
//Info<< "codePath:" << codePath << nl
|
||||
// << "libPath:" << libPath << endl;
|
||||
// NOTE: probably don't need codeProperties anymore
|
||||
// since we use the sha1 directly
|
||||
if (!useInlineDict)
|
||||
{
|
||||
this->dict().setUnmodified();
|
||||
}
|
||||
|
||||
|
||||
// write code into redirectType_ subdir as well
|
||||
dynamicCode dynCode(redirectType_);
|
||||
|
||||
// The version function name - based on the SHA1
|
||||
const string checkFuncName
|
||||
(
|
||||
dynCode.codeName() + "_" + context.sha1().str()
|
||||
);
|
||||
|
||||
|
||||
const fileName libPath = dynCode.libPath();
|
||||
void* lib = dlLibraryTable::findLibrary(libPath);
|
||||
|
||||
|
||||
// TODO:
|
||||
// calculate old/new SHA1 for code
|
||||
// check if the correct library version was already loaded.
|
||||
// Find the library handle.
|
||||
//
|
||||
// string signatureName(redirectType_ + "_" + sha().str());
|
||||
// void (*signatureFunction)();
|
||||
// signatureFunction = reinterpret_cast<void(*)()>(dlSym(lib, signatureName));
|
||||
|
||||
if (dict_.found("code"))
|
||||
// Load library if not already loaded
|
||||
bool reusing = false;
|
||||
if (!lib && dlLibraryTable::open(libPath, false))
|
||||
{
|
||||
if (!lib)
|
||||
{
|
||||
writeLibrary(codePath, libPath, dict_);
|
||||
}
|
||||
lib = dlLibraryTable::findLibrary(libPath);
|
||||
reusing = true;
|
||||
}
|
||||
else
|
||||
|
||||
|
||||
// library may have loaded, the version may not be correct
|
||||
bool waiting = false;
|
||||
if (lib)
|
||||
{
|
||||
const codeProperties& onTheFlyDict = dict();
|
||||
|
||||
if (onTheFlyDict.modified())
|
||||
// Unload library if needed
|
||||
if (!dlSym(lib, checkFuncName))
|
||||
{
|
||||
onTheFlyDict.setUnmodified();
|
||||
|
||||
// Remove instantiation of fvPatchField provided by library
|
||||
redirectPatchFieldPtr_.clear();
|
||||
// Unload library
|
||||
if (lib)
|
||||
reusing = false;
|
||||
waiting = true;
|
||||
if (!dlLibraryTable::close(libPath, false))
|
||||
{
|
||||
if (!dlLibraryTable::close(libPath))
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
"codedFixedValueFvPatchScalarField::updateLibrary(..)",
|
||||
onTheFlyDict
|
||||
) << "Failed unloading library " << libPath
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
lib = NULL;
|
||||
FatalIOErrorIn
|
||||
(
|
||||
"codedFixedValueFvPatchScalarField::updateLibrary(..)",
|
||||
context.dict()
|
||||
) << "Failed unloading library "
|
||||
<< libPath
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
const dictionary& codeDict = onTheFlyDict.subDict(redirectType_);
|
||||
writeLibrary(codePath, libPath, codeDict);
|
||||
lib = 0;
|
||||
}
|
||||
|
||||
// unload from all processes
|
||||
reduce(waiting, orOp<bool>());
|
||||
}
|
||||
|
||||
|
||||
// create library
|
||||
if (!lib)
|
||||
{
|
||||
if (useInlineDict)
|
||||
{
|
||||
createLibrary(dynCode, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove instantiation of fvPatchField provided by library
|
||||
redirectPatchFieldPtr_.clear();
|
||||
createLibrary(dynCode, context);
|
||||
}
|
||||
|
||||
if (Pstream::master())
|
||||
{
|
||||
const Foam::string wmakeCmd("wmake libso " + codePath);
|
||||
Info<< "Invoking " << wmakeCmd << endl;
|
||||
if (Foam::system(wmakeCmd))
|
||||
if (!dynCode.wmakeLibso())
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
"codedFixedValueFvPatchScalarField::updateLibrary()",
|
||||
dict_
|
||||
) << "Failed " << wmakeCmd
|
||||
) << "Failed wmake " << libPath
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
}
|
||||
|
||||
// all processes must wait for compile
|
||||
bool dummy = true;
|
||||
reduce(dummy, orOp<bool>());
|
||||
waiting = true;
|
||||
reduce(waiting, orOp<bool>());
|
||||
|
||||
if (!dlLibraryTable::open(libPath))
|
||||
if (!dlLibraryTable::open(libPath, false))
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
@ -293,6 +247,29 @@ void Foam::codedFixedValueFvPatchScalarField::updateLibrary()
|
||||
) << "Failed loading library " << libPath
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
|
||||
// paranoid - check that signature function is really there
|
||||
lib = dlLibraryTable::findLibrary(libPath);
|
||||
if (lib)
|
||||
{
|
||||
if (!dlSym(lib, checkFuncName))
|
||||
{
|
||||
FatalIOErrorIn
|
||||
(
|
||||
"codedFixedValueFvPatchScalarField::updateLibrary(..)",
|
||||
dict_
|
||||
) << "Library loaded - but wrong version!"
|
||||
<< libPath
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
lib = 0;
|
||||
}
|
||||
}
|
||||
else if (reusing)
|
||||
{
|
||||
Info<< "Reusing library in " << libPath << nl
|
||||
<< " with " << context.sha1().str() << nl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -29,8 +29,6 @@ Description
|
||||
Constructs on-the-fly a new boundary condition (derived from
|
||||
fixedValueFvPatchScalarField) which is then used to evaluate.
|
||||
|
||||
See also codeStream.
|
||||
|
||||
Example:
|
||||
\verbatim
|
||||
movingWall
|
||||
@ -71,7 +69,7 @@ Description
|
||||
\endverbatim
|
||||
|
||||
SeeAlso
|
||||
Foam::codeStreamTools for constant paths used
|
||||
Foam::dynamicCode and Foam::functionEntries::codeStream
|
||||
|
||||
SourceFiles
|
||||
codedFixedValueFvPatchScalarField.C
|
||||
@ -82,14 +80,16 @@ SourceFiles
|
||||
#define codedFixedValueFvPatchScalarField_H
|
||||
|
||||
#include "fixedValueFvPatchFields.H"
|
||||
#include "SHA1Digest.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Forward declaration of classes
|
||||
class codeProperties;
|
||||
class dynamicCode;
|
||||
class dynamicCodeContext;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class codedFixedValueFvPatchScalarField Declaration
|
||||
@ -104,10 +104,6 @@ class codedFixedValueFvPatchScalarField
|
||||
//- Dictionary contents for the boundary condition
|
||||
mutable dictionary dict_;
|
||||
|
||||
//- SHA1Digest of the Dictionary contents
|
||||
// Currently unused, but useful for reloading?
|
||||
mutable SHA1Digest sha1_;
|
||||
|
||||
const word redirectType_;
|
||||
|
||||
mutable autoPtr<fvPatchScalarField> redirectPatchFieldPtr_;
|
||||
@ -117,12 +113,7 @@ class codedFixedValueFvPatchScalarField
|
||||
|
||||
const codeProperties& dict() const;
|
||||
|
||||
void writeLibrary
|
||||
(
|
||||
const fileName& dir,
|
||||
const fileName& libPath,
|
||||
const dictionary& dict
|
||||
);
|
||||
void createLibrary(dynamicCode&, const dynamicCodeContext& dict);
|
||||
|
||||
void updateLibrary();
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ License
|
||||
|
||||
#include "systemCall.H"
|
||||
#include "Time.H"
|
||||
#include "codeStreamTools.H"
|
||||
#include "dynamicCode.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
@ -71,7 +71,7 @@ void Foam::systemCall::read(const dictionary& dict)
|
||||
<< "no executeCalls, endCalls or writeCalls defined."
|
||||
<< endl;
|
||||
}
|
||||
else if (!codeStreamTools::allowSystemOperations)
|
||||
else if (!dynamicCode::allowSystemOperations)
|
||||
{
|
||||
FatalErrorIn
|
||||
(
|
||||
|
||||
Reference in New Issue
Block a user