ENH: support additional command-line loading of libraries (#1414)

- this can be useful for preloading of libraries, or for utilities
  that don't use system/controlDict.

  The additional libraries can be specified individually:

      myUtil -lib lib1 -lib lib2 -lib lib3

  When specified like this, the options add up.

  Or as a 'captured' list using OpenFOAM's standard arg list handling:

      myUtil -lib '(' lib1  lib2 lib3 ')'
      myUtil -lib \( lib1  lib2 lib3 \)

  or as single argument list:

      myUtil -lib '("lib1" "lib2" "lib3")'

  When specified as a single argument, would normally take advantage
  of the transparent handling of word vs fileName and omit the string
  quotes:

      myUtil -lib '(lib1 lib2 lib3)'

ENH: dlOpen error messages now propagated into dlLibraryTable

- this makes the context more relevant and also avoids the previous
  annoyance of double warnings (one from the POSIX loader, and one
  from dlLibraryTable)

STYLE: mark -noFunctionObjects and -withFunctionObjects as 'advanced'

- reduces clutter. Still visible with -help-full
This commit is contained in:
Mark Olesen 2019-08-30 15:33:29 +02:00 committed by Andrew Heather
parent 894645f9e1
commit 6eaa326cec
10 changed files with 411 additions and 115 deletions

View File

@ -1223,8 +1223,7 @@ void* Foam::dlOpen(const fileName& libName, const bool check)
else if (check)
{
WarningInFunction
<< "dlopen error : " << MSwindows::lastError()
<< endl;
<< "dlopen error : " << MSwindows::lastError() << endl;
}
if (MSwindows::debug)
@ -1239,6 +1238,26 @@ void* Foam::dlOpen(const fileName& libName, const bool check)
}
void* Foam::dlOpen(const fileName& libName, std::string& errorMsg)
{
// Call without emitting error message - we capture that ourselves
void* handle = Foam::dlOpen(libName, false);
if (!handle)
{
// Capture error message
errorMsg = MSwindows::lastError();
}
else
{
// No errors
errorMsg.clear();
}
return handle;
}
Foam::label Foam::dlOpen
(
std::initializer_list<fileName> libNames,

View File

@ -1711,8 +1711,7 @@ void* Foam::dlOpen(const fileName& libName, const bool check)
if (!handle && check)
{
WarningInFunction
<< "dlopen error : " << ::dlerror()
<< endl;
<< "dlopen error : " << ::dlerror() << endl;
}
if (POSIX::debug)
@ -1727,6 +1726,26 @@ void* Foam::dlOpen(const fileName& libName, const bool check)
}
void* Foam::dlOpen(const fileName& libName, std::string& errorMsg)
{
// Call without emitting error message - we capture that ourselves
void* handle = Foam::dlOpen(libName, false);
if (!handle)
{
// Capture error message
errorMsg = ::dlerror();
}
else
{
// No errors
errorMsg.clear();
}
return handle;
}
Foam::label Foam::dlOpen
(
std::initializer_list<fileName> libNames,

View File

@ -524,11 +524,11 @@ Foam::Time::Time
runTimeModifiable_(false),
functionObjects_(*this, false)
{
// Enable/disable functions
// Functions
//
// '-withFunctionObjects' exists and used = enable
// '-noFunctionObjects' exists and used = disable
// default: no functions if there is no way to enable/disable them
// * '-withFunctionObjects' exists and used = enable
// * '-noFunctionObjects' exists and used = disable
// * default: no functions if there is no way to enable/disable them
if
(
argList::validOptions.found("withFunctionObjects")
@ -541,16 +541,10 @@ Foam::Time::Time
functionObjects_.on();
}
// Allow/disallow libs
// Libraries
//
// '-no-libs' exists and used = disable
// default: enable
if
(
argList::validOptions.found("no-libs")
? !args.found("no-libs")
: true
)
// * enabled unless '-no-libs' option was used
if (!args.found("no-libs"))
{
libs_.open(controlDict_, "libs");
}
@ -619,7 +613,6 @@ Foam::Time::Time
writeStreamOption_(IOstream::ASCII),
graphFormat_("raw"),
runTimeModifiable_(false),
functionObjects_(*this, false)
{
if (enableFunctionObjects)
@ -694,7 +687,6 @@ Foam::Time::Time
writeStreamOption_(IOstream::ASCII),
graphFormat_("raw"),
runTimeModifiable_(false),
functionObjects_(*this, false)
{
if (enableFunctionObjects)

View File

@ -27,6 +27,7 @@ License
#include "dlLibraryTable.H"
#include "OSspecific.H"
#include "IOstreams.H"
#include "int.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -37,10 +38,47 @@ namespace Foam
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void* Foam::dlLibraryTable::openLibrary
(
const fileName& libName,
bool verbose
)
{
if (libName.empty())
{
return nullptr;
}
std::string msg;
void* ptr = Foam::dlOpen(fileName(libName).expand(), msg);
DebugInFunction
<< "Opened " << libName
<< " resulting in handle " << Foam::name(ptr) << nl;
if (!ptr)
{
// Even with details turned off, we want some feedback about failure
OSstream& os = (verbose ? WarningInFunction : Serr);
os << "Could not load " << libName << nl << msg.c_str() << endl;
}
return ptr;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::dlLibraryTable::dlLibraryTable()
{}
Foam::dlLibraryTable::dlLibraryTable
(
const UList<fileName>& libNames,
bool verbose
)
{
dlLibraryTable::open(libNames, verbose);
}
Foam::dlLibraryTable::dlLibraryTable
@ -49,7 +87,7 @@ Foam::dlLibraryTable::dlLibraryTable
const word& libsEntry
)
{
open(dict, libsEntry);
dlLibraryTable::open(dict, libsEntry);
}
@ -57,87 +95,225 @@ Foam::dlLibraryTable::dlLibraryTable
Foam::dlLibraryTable::~dlLibraryTable()
{
forAllReverse(libPtrs_, i)
{
if (libPtrs_[i])
{
DebugInFunction
<< "Closing " << libNames_[i]
<< " with handle " << name(libPtrs_[i]) << nl;
if (!dlClose(libPtrs_[i]))
{
WarningInFunction<< "Failed closing " << libNames_[i]
<< " with handle " << name(libPtrs_[i]) << endl;
}
}
}
clear();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::dlLibraryTable::open
(
const fileName& libName,
const bool verbose
)
bool Foam::dlLibraryTable::empty() const
{
if (libName.empty())
for (const void* ptr : libPtrs_)
{
if (ptr != nullptr)
{
return false;
}
}
return true;
}
Foam::label Foam::dlLibraryTable::size() const
{
label nLoaded = 0;
for (const void* ptr : libPtrs_)
{
if (ptr != nullptr)
{
++nLoaded;
}
}
return nLoaded;
}
void Foam::dlLibraryTable::clear(bool verbose)
{
label nLoaded = 0;
forAllReverse(libPtrs_, i)
{
void* ptr = libPtrs_[i];
if (ptr == nullptr)
{
libNames_[i].clear();
}
else if (Foam::dlClose(ptr))
{
DebugInFunction
<< "Closed [" << i << "] " << libNames_[i]
<< " with handle " << Foam::name(ptr) << nl;
libPtrs_[i] = nullptr;
libNames_[i].clear();
}
else
{
++nLoaded; // Still loaded
if (verbose)
{
WarningInFunction
<< "Failed closing " << libNames_[i]
<< " with handle " << Foam::name(ptr) << endl;
}
}
}
// Compact the lists
if (nLoaded && nLoaded != libPtrs_.size())
{
nLoaded = 0;
forAll(libPtrs_, i)
{
if (libPtrs_[i] != nullptr)
{
if (nLoaded != i)
{
libPtrs_[nLoaded] = libPtrs_[i];
libNames_[nLoaded] = std::move(libNames_[i]);
}
++nLoaded;
}
}
}
libPtrs_.resize(nLoaded);
libNames_.resize(nLoaded);
}
bool Foam::dlLibraryTable::append(const fileName& libName)
{
if (libName.empty() || libNames_.found(libName))
{
return false;
}
void* ptr = dlOpen(fileName(libName).expand(), verbose);
libPtrs_.append(nullptr);
libNames_.append(libName);
DebugInFunction
<< "Opened " << libName
<< " resulting in handle " << name(ptr) << endl;
return true;
}
Foam::label Foam::dlLibraryTable::append(const UList<fileName>& libNames)
{
label nAdded = 0;
for (const fileName& libName : libNames)
{
if (append(libName))
{
++nAdded;
}
}
return nAdded;
}
bool Foam::dlLibraryTable::open(bool verbose)
{
label nOpen = 0;
label nCand = 0; // Number of candidates (have libName but no pointer)
forAll(libPtrs_, i)
{
const fileName& libName = libNames_[i];
if (libPtrs_[i] == nullptr && !libName.empty())
{
++nCand;
void* ptr = openLibrary(libName, verbose);
if (ptr)
{
++nOpen;
libPtrs_[i] = ptr;
}
else
{
libNames_[i].clear(); // Avoid trying again
}
}
}
return nOpen && nOpen == nCand;
}
void* Foam::dlLibraryTable::open
(
const fileName& libName,
bool verbose
)
{
void* ptr = openLibrary(libName, verbose);
if (ptr)
{
libPtrs_.append(ptr);
libNames_.append(libName);
return true;
}
if (verbose)
return ptr;
}
bool Foam::dlLibraryTable::open
(
const UList<fileName>& libNames,
bool verbose
)
{
label nOpen = 0;
for (const fileName& libName : libNames)
{
WarningInFunction
<< "could not load " << libName
<< endl;
const label index = libNames_.find(libName);
if (index >= 0 && libPtrs_[index] != nullptr)
{
// Already known and opened
++nOpen;
}
else if (dlLibraryTable::open(libName, verbose))
{
++nOpen;
}
}
return false;
return nOpen && nOpen == libNames.size();
}
bool Foam::dlLibraryTable::close
(
const fileName& libName,
const bool verbose
bool verbose
)
{
label index = -1;
forAllReverse(libNames_, i)
{
if (libName == libNames_[i])
{
index = i;
break;
}
}
const label index = libNames_.rfind(libName);
if (index == -1)
if (index < 0)
{
return false;
}
DebugInFunction
<< "Closing " << libName
<< " with handle " << name(libPtrs_[index]) << nl;
<< " with handle " << Foam::name(libPtrs_[index]) << nl;
const bool ok = dlClose(libPtrs_[index]);
const bool ok = Foam::dlClose(libPtrs_[index]);
libPtrs_[index] = nullptr;
libNames_[index].clear();
@ -145,8 +321,7 @@ bool Foam::dlLibraryTable::close
if (!ok && verbose)
{
WarningInFunction
<< "could not close " << libName
<< endl;
<< "Could not close " << libName << endl;
}
return ok;
@ -155,22 +330,14 @@ bool Foam::dlLibraryTable::close
void* Foam::dlLibraryTable::findLibrary(const fileName& libName)
{
label index = -1;
forAllReverse(libNames_, i)
const label index = libNames_.rfind(libName);
if (index < 0)
{
if (libName == libNames_[i])
{
index = i;
break;
}
return nullptr;
}
if (index != -1)
{
return libPtrs_[index];
}
return nullptr;
return libPtrs_[index];
}
@ -187,7 +354,7 @@ bool Foam::dlLibraryTable::open
for (const fileName& libName : libNames)
{
if (dlLibraryTable::open(libName))
if (dlLibraryTable::open(libName)) // verbose = true
{
++nOpen;
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\ / A nd | Copyright (C) 2018-2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
| Copyright (C) 2011-2016 OpenFOAM Foundation
@ -27,7 +27,7 @@ Class
Foam::dlLibraryTable
Description
A table of dynamically loaded libraries
A table of dynamically loaded libraries.
SourceFiles
dlLibraryTable.C
@ -37,7 +37,6 @@ SourceFiles
#ifndef dlLibraryTable_H
#define dlLibraryTable_H
#include "label.H"
#include "DynamicList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -51,7 +50,7 @@ namespace Foam
class dlLibraryTable
{
// Private data
// Private Data
DynamicList<void*> libPtrs_;
@ -60,6 +59,10 @@ class dlLibraryTable
// Private Member Functions
//- Open specified library name and return pointer.
// Warning messages, but no additional side-effects.
void* openLibrary(const fileName& libName, bool verbose);
//- No copy construct
dlLibraryTable(const dlLibraryTable&) = delete;
@ -75,24 +78,59 @@ public:
// Constructors
//- Construct null
dlLibraryTable();
dlLibraryTable() = default;
//- Move construct
dlLibraryTable(dlLibraryTable&&) = default;
//- Open specified libraries. Ignores duplicate names.
explicit dlLibraryTable
(
const UList<fileName>& libNames,
bool verbose = true
);
//- Open all libraries listed in the 'libsEntry' entry in the
//- given dictionary.
//- given dictionary. Verbose = true.
dlLibraryTable(const dictionary& dict, const word& libsEntry);
//- Destructor
//- Destructor. Closes all libraries loaded by the table.
~dlLibraryTable();
// Member Functions
//- Open the named library, optionally with warnings if problems occur
bool open(const fileName& libName, const bool verbose = true);
//- True if no there are no libraries loaded by the table
bool empty() const;
//- Close the named library, optionally with warnings if problems occur
bool close(const fileName& libName, const bool verbose = true);
//- The number of libraries loaded by the table
label size() const;
//- Clearing closes all libraries loaded by the table.
void clear(bool verbose = true);
//- Add to the list of names, but do not yet open.
// Ignores duplicate names.
bool append(const fileName& libName);
//- Add to the list of names, but do not yet open.
// Ignores duplicate names.
label append(const UList<fileName>& libNames);
//- Open named, but unopened libraries.
//- These names will normally have been added with the append() method.
bool open(bool verbose = true);
//- Open the named library, optionally warn if problems occur
void* open(const fileName& libName, bool verbose = true);
//- Open the named libraries, optionally warn if problems occur
// Ignores duplicate names.
bool open(const UList<fileName>& libNames, bool verbose = true);
//- Close the named library, optionally warn if problems occur
bool close(const fileName& libName, bool verbose = true);
//- Find the handle of the named library
void* findLibrary(const fileName& libName);
@ -111,6 +149,12 @@ public:
const word& libsEntry,
const TablePtr& tablePtr
);
// Member Operators
//- Move assignment
dlLibraryTable& operator=(dlLibraryTable&&) = default;
};

View File

@ -76,6 +76,14 @@ Foam::argList::initValidTables::initValidTables()
"dir",
"Specify case directory to use (instead of the cwd)"
);
argList::addOption
(
"lib",
"name",
"Additional library/libraries to load (can be used multiple times)",
true // advanced option
);
argList::addBoolOption("parallel", "Run in parallel");
validParOptions.set("parallel", "");
argList::addOption
@ -114,7 +122,8 @@ Foam::argList::initValidTables::initValidTables()
argList::addBoolOption
(
"noFunctionObjects",
"Do not execute function objects"
"Do not execute function objects",
true // advanced option
);
argList::addOption
@ -412,7 +421,8 @@ void Foam::argList::noFunctionObjects(bool addWithOption)
addBoolOption
(
"withFunctionObjects",
"Execute functionObjects"
"Execute functionObjects",
true // advanced option
);
}
}
@ -430,7 +440,7 @@ void Foam::argList::noLibs()
(
"no-libs",
"Disable use of the controlDict libs entry",
true // advanced
true // advanced option
);
}
@ -698,10 +708,11 @@ Foam::argList::argList
)
:
args_(argc),
options_(argc)
options_(argc),
libs_()
{
// Check for -fileHandler, which requires an argument.
word handlerType(getEnv("FOAM_FILEHANDLER"));
word handlerType;
for (int argi = argc-2; argi > 0; --argi)
{
if (argv[argi][0] == '-')
@ -717,7 +728,11 @@ Foam::argList::argList
}
if (handlerType.empty())
{
handlerType = fileOperation::defaultFileHandler;
handlerType = Foam::getEnv("FOAM_FILEHANDLER");
if (handlerType.empty())
{
handlerType = fileOperation::defaultFileHandler;
}
}
// Detect any parallel options
@ -793,8 +808,19 @@ Foam::argList::argList
commandLine_ += ' ';
commandLine_ += args_[argi];
// Handle duplicates by taking the last -option specified
options_.set(optName, args_[argi]);
if (strcmp(optName, "lib") == 0)
{
// The '-lib' option:
// Append name(s) to libs_ for later opening
libs_.append(this->getList<fileName>(argi));
}
else
{
// Regular option:
// Duplicates handled by using the last -option specified
options_.set(optName, args_[argi]);
}
}
else
{
@ -832,6 +858,7 @@ Foam::argList::argList
parRunControl_(args.parRunControl_),
args_(args.args_),
options_(options),
libs_(),
executable_(args.executable_),
rootPath_(args.rootPath_),
globalCase_(args.globalCase_),
@ -972,26 +999,29 @@ void Foam::argList::parse
}
jobInfo.add("foamBuild", build);
}
// Load additional libraries
libs_.open(bannerEnabled());
}
// Set fileHandler. In increasing order of priority:
// 1. default = uncollated
// 2. environment var FOAM_FILEHANDLER
// 2. env variable "FOAM_FILEHANDLER"
// 3. etc/controlDict optimisationSwitches 'fileHandler'
// 4. system/controlDict 'fileHandler' (not handled here; done in TimeIO.C)
// 5. '-fileHandler' commmand-line option
{
word fileHandlerName =
options_.lookup("fileHandler", getEnv("FOAM_FILEHANDLER"));
word handlerType =
options_.lookup("fileHandler", Foam::getEnv("FOAM_FILEHANDLER"));
if (fileHandlerName.empty())
if (handlerType.empty())
{
fileHandlerName = fileOperation::defaultFileHandler;
handlerType = fileOperation::defaultFileHandler;
}
auto handler = fileOperation::New(fileHandlerName, bannerEnabled());
auto handler = fileOperation::New(handlerType, bannerEnabled());
Foam::fileHandler(handler);
}

View File

@ -99,15 +99,13 @@ SourceFiles
#define argList_H
#include "stringList.H"
#include "SubList.H"
#include "SLList.H"
#include "HashSet.H"
#include "HashTable.H"
#include "word.H"
#include "fileName.H"
#include "parRun.H"
#include "OSspecific.H"
#include "ITstream.H"
#include "dlLibraryTable.H"
#include "OSspecific.H"
#include <utility>
// Transitional features - older style access (including 1712 release)
@ -142,6 +140,9 @@ class argList
//- The extracted options
HashTable<string> options_;
//- Additional libraries
dlLibraryTable libs_;
word executable_;
fileName rootPath_;
fileName globalCase_;
@ -194,7 +195,7 @@ class argList
public:
// Static data members
// Static Data Members
//- A list of valid (mandatory) arguments
static SLList<string> validArgs;
@ -235,6 +236,7 @@ public:
static word postProcessOptionName;
//! \cond internalClass
// The constructor populates the standard options
struct initValidTables
{
initValidTables();
@ -340,7 +342,13 @@ public:
//- Return the ParRunControl
inline const ParRunControl& parRunControl() const;
//- Return the number of arguments
//- Access to the loaded libraries
inline const dlLibraryTable& libs() const;
//- Access to the loaded libraries
inline dlLibraryTable& libs();
//- The number of arguments
inline label size() const;
//- Return arguments
@ -703,7 +711,6 @@ public:
}
#endif /* Foam_argList_1712 */
};

View File

@ -111,6 +111,18 @@ inline const Foam::ParRunControl& Foam::argList::parRunControl() const
}
inline const Foam::dlLibraryTable& Foam::argList::libs() const
{
return libs_;
}
inline Foam::dlLibraryTable& Foam::argList::libs()
{
return libs_;
}
inline Foam::label Foam::argList::size() const
{
return args_.size();

View File

@ -94,7 +94,8 @@ const std::string Foam::foamVersion::buildArch
#elif defined (WM_BIG_ENDIAN)
"MSB"
#else
"???"
#warning Cannot determine BIG or LITTLE endian. This should never happen.
"_SB"
#endif
";label=" + std::to_string(8*sizeof(Foam::label))
+ ";scalar=" + std::to_string(8*sizeof(Foam::scalar))

View File

@ -257,6 +257,11 @@ int system(const CStringList& command, const bool bg = false);
// Prints warning if a library cannot be loaded (suppress with check=false)
void* dlOpen(const fileName& libName, const bool check=true);
//- Open a shared library and return handle to library.
// A leading "lib" and ".so" suffix are added silently as required.
// Captures any error messages in the second parameter (empty if no errors).
void* dlOpen(const fileName& libName, std::string& errorMsg);
//- Open shared libraries and return number of libraries loaded.
// A leading "lib" and ".so" suffix are added silently as required.
// Prints warning if a library cannot be loaded (suppress with check=false)