mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
559 lines
13 KiB
C
559 lines
13 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#include "dynamicCode.H"
|
|
#include "dynamicCodeContext.H"
|
|
#include "stringOps.H"
|
|
#include "IFstream.H"
|
|
#include "OFstream.H"
|
|
#include "OSspecific.H"
|
|
#include "dictionary.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";
|
|
|
|
const char* const Foam::dynamicCode::libTargetRoot =
|
|
"LIB = $(PWD)/../platforms/$(WM_OPTIONS)/lib/lib";
|
|
|
|
const char* const Foam::dynamicCode::topDirName = "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);
|
|
}
|
|
|
|
if (!allowSystemOperations)
|
|
{
|
|
FatalIOErrorIn
|
|
(
|
|
title,
|
|
dict
|
|
) << "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(FatalIOError);
|
|
}
|
|
}
|
|
|
|
|
|
Foam::word Foam::dynamicCode::libraryBaseName(const fileName& libPath)
|
|
{
|
|
word libName(libPath.name(true));
|
|
libName.erase(0, 3); // remove leading 'lib' from name
|
|
return libName;
|
|
}
|
|
|
|
|
|
|
|
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
|
|
|
void Foam::dynamicCode::copyAndFilter
|
|
(
|
|
ISstream& is,
|
|
OSstream& os,
|
|
const HashTable<string>& mapping
|
|
)
|
|
{
|
|
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.writeQuoted(line, false) << nl;
|
|
}
|
|
while (is.good());
|
|
}
|
|
|
|
|
|
bool Foam::dynamicCode::resolveTemplates
|
|
(
|
|
const UList<fileName>& templateNames,
|
|
DynamicList<fileName>& resolvedFiles,
|
|
DynamicList<fileName>& badFiles
|
|
)
|
|
{
|
|
// try to get template from FOAM_CODESTREAM_TEMPLATES
|
|
const fileName templateDir(Foam::getEnv(codeTemplateEnvName));
|
|
|
|
bool allOkay = true;
|
|
forAll(templateNames, fileI)
|
|
{
|
|
const fileName& templateName = templateNames[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);
|
|
allOkay = false;
|
|
}
|
|
else
|
|
{
|
|
resolvedFiles.append(file);
|
|
}
|
|
}
|
|
|
|
return allOkay;
|
|
}
|
|
|
|
|
|
bool Foam::dynamicCode::writeCommentSHA1(Ostream& os) const
|
|
{
|
|
const bool hasSHA1 = filterVars_.found("SHA1sum");
|
|
|
|
if (hasSHA1)
|
|
{
|
|
os << "/* dynamicCode:\n * SHA1 = ";
|
|
os.writeQuoted(filterVars_["SHA1sum"], false) << "\n */\n";
|
|
}
|
|
|
|
return hasSHA1;
|
|
}
|
|
|
|
|
|
bool Foam::dynamicCode::createMakeFiles() const
|
|
{
|
|
// Create Make/files
|
|
if (compileFiles_.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const fileName dstFile(this->codePath()/"Make/files");
|
|
|
|
// Create dir
|
|
mkDir(dstFile.path());
|
|
|
|
OFstream os(dstFile);
|
|
//Info<< "Writing to " << dstFile << endl;
|
|
if (!os.good())
|
|
{
|
|
FatalErrorIn
|
|
(
|
|
"dynamicCode::createMakeFiles()"
|
|
" const"
|
|
) << "Failed writing " << dstFile
|
|
<< exit(FatalError);
|
|
}
|
|
|
|
writeCommentSHA1(os);
|
|
|
|
// Write compile files
|
|
forAll(compileFiles_, fileI)
|
|
{
|
|
os.writeQuoted(compileFiles_[fileI], false) << nl;
|
|
}
|
|
|
|
os << nl
|
|
<< libTargetRoot << codeName_.c_str() << nl;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Foam::dynamicCode::createMakeOptions() const
|
|
{
|
|
// Create Make/options
|
|
if (compileFiles_.empty() || makeOptions_.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const fileName dstFile(this->codePath()/"Make/options");
|
|
|
|
// Create dir
|
|
mkDir(dstFile.path());
|
|
|
|
OFstream os(dstFile);
|
|
//Info<< "Writing to " << dstFile << endl;
|
|
if (!os.good())
|
|
{
|
|
FatalErrorIn
|
|
(
|
|
"dynamicCode::createMakeOptions()"
|
|
" const"
|
|
) << "Failed writing " << dstFile
|
|
<< exit(FatalError);
|
|
}
|
|
|
|
writeCommentSHA1(os);
|
|
os.writeQuoted(makeOptions_, false) << nl;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Foam::dynamicCode::writeDigest(const SHA1Digest& sha1) const
|
|
{
|
|
const fileName file = digestFile();
|
|
mkDir(file.path());
|
|
|
|
OFstream os(file);
|
|
sha1.write(os, true) << nl;
|
|
|
|
return os.good();
|
|
}
|
|
|
|
|
|
bool Foam::dynamicCode::writeDigest(const std::string& sha1) const
|
|
{
|
|
const fileName file = digestFile();
|
|
mkDir(file.path());
|
|
|
|
OFstream os(file);
|
|
os << '_';
|
|
os.writeQuoted(sha1, false) << nl;
|
|
|
|
return os.good();
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
|
|
|
Foam::dynamicCode::dynamicCode(const word& codeName, const word& codeDirName)
|
|
:
|
|
codeRoot_(stringOps::expand("$FOAM_CASE")/topDirName),
|
|
libSubDir_(stringOps::expand("platforms/$WM_OPTIONS/lib")),
|
|
codeName_(codeName),
|
|
codeDirName_(codeDirName)
|
|
{
|
|
if (codeDirName_.empty())
|
|
{
|
|
codeDirName_ = codeName_;
|
|
}
|
|
|
|
clear();
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
|
|
|
Foam::fileName Foam::dynamicCode::codeRelPath() const
|
|
{
|
|
return topDirName/codeDirName_;
|
|
}
|
|
|
|
|
|
Foam::fileName Foam::dynamicCode::libRelPath() const
|
|
{
|
|
return codeRelPath()/libSubDir_/"lib" + codeName_ + ".so";
|
|
}
|
|
|
|
|
|
void Foam::dynamicCode::clear()
|
|
{
|
|
compileFiles_.clear();
|
|
copyFiles_.clear();
|
|
createFiles_.clear();
|
|
filterVars_.clear();
|
|
filterVars_.set("typeName", codeName_);
|
|
filterVars_.set("SHA1sum", SHA1Digest().str());
|
|
|
|
// provide default Make/options
|
|
makeOptions_ =
|
|
"EXE_INC = -g\n"
|
|
"\n\nLIB_LIBS = ";
|
|
}
|
|
|
|
|
|
void Foam::dynamicCode::reset
|
|
(
|
|
const dynamicCodeContext& context
|
|
)
|
|
{
|
|
clear();
|
|
setFilterContext(context);
|
|
}
|
|
|
|
|
|
void Foam::dynamicCode::addCompileFile(const fileName& name)
|
|
{
|
|
compileFiles_.append(name);
|
|
}
|
|
|
|
|
|
void Foam::dynamicCode::addCopyFile(const fileName& name)
|
|
{
|
|
copyFiles_.append(name);
|
|
}
|
|
|
|
|
|
void Foam::dynamicCode::addCreateFile
|
|
(
|
|
const fileName& name,
|
|
const string& contents
|
|
)
|
|
{
|
|
createFiles_.append(fileAndContent(name, contents));
|
|
}
|
|
|
|
|
|
void Foam::dynamicCode::setFilterContext
|
|
(
|
|
const dynamicCodeContext& context
|
|
)
|
|
{
|
|
filterVars_.set("localCode", context.localCode());
|
|
filterVars_.set("code", context.code());
|
|
filterVars_.set("codeInclude", context.include());
|
|
filterVars_.set("SHA1sum", context.sha1().str());
|
|
}
|
|
|
|
|
|
void Foam::dynamicCode::setFilterVariable
|
|
(
|
|
const word& key,
|
|
const std::string& value
|
|
)
|
|
{
|
|
filterVars_.set(key, value);
|
|
}
|
|
|
|
|
|
void Foam::dynamicCode::setMakeOptions(const std::string& content)
|
|
{
|
|
makeOptions_ = content;
|
|
}
|
|
|
|
|
|
bool Foam::dynamicCode::copyOrCreateFiles(const bool verbose) const
|
|
{
|
|
if (verbose)
|
|
{
|
|
Info<< "Creating new library in " << this->libRelPath() << endl;
|
|
}
|
|
|
|
const label nFiles = compileFiles_.size() + copyFiles_.size();
|
|
|
|
DynamicList<fileName> resolvedFiles(nFiles);
|
|
DynamicList<fileName> badFiles(nFiles);
|
|
|
|
// resolve template, or add to bad-files
|
|
resolveTemplates(compileFiles_, resolvedFiles, badFiles);
|
|
resolveTemplates(copyFiles_, resolvedFiles, badFiles);
|
|
|
|
if (!badFiles.empty())
|
|
{
|
|
FatalErrorIn
|
|
(
|
|
"dynamicCode::copyFilesContents(..)"
|
|
) << "Could not find the code template(s): "
|
|
<< badFiles << nl
|
|
<< "Under the $" << codeTemplateEnvName
|
|
<< " directory or via via the ~OpenFOAM/"
|
|
<< codeTemplateDirName << " expansion"
|
|
<< exit(FatalError);
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
}
|
|
|
|
// Copy lines while expanding variables
|
|
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::copyOrCreateFiles()"
|
|
" const"
|
|
) << "Failed writing " << dstFile
|
|
<< exit(FatalError);
|
|
}
|
|
os.writeQuoted(createFiles_[fileI].second(), false) << nl;
|
|
}
|
|
|
|
|
|
// Create Make/files + Make/options
|
|
createMakeFiles();
|
|
createMakeOptions();
|
|
|
|
writeDigest(filterVars_["SHA1sum"]);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Foam::dynamicCode::wmakeLibso() const
|
|
{
|
|
const Foam::string wmakeCmd("wmake -s libso " + this->codePath());
|
|
Info<< "Invoking " << wmakeCmd << endl;
|
|
|
|
if (Foam::system(wmakeCmd))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
bool Foam::dynamicCode::upToDate(const SHA1Digest& sha1) const
|
|
{
|
|
const fileName file = digestFile();
|
|
|
|
if (!exists(file, false) || SHA1Digest(IFstream(file)()) != sha1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Foam::dynamicCode::upToDate(const dynamicCodeContext& context) const
|
|
{
|
|
return upToDate(context.sha1());
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|