From 6eaa326cec11cc4159768d538bd49fbd5a1d3823 Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Fri, 30 Aug 2019 15:33:29 +0200 Subject: [PATCH] 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 --- src/OSspecific/MSwindows/MSwindows.C | 23 +- src/OSspecific/POSIX/POSIX.C | 23 +- src/OpenFOAM/db/Time/Time.C | 22 +- .../dlLibraryTable/dlLibraryTable.C | 293 ++++++++++++++---- .../dlLibraryTable/dlLibraryTable.H | 66 +++- src/OpenFOAM/global/argList/argList.C | 58 +++- src/OpenFOAM/global/argList/argList.H | 21 +- src/OpenFOAM/global/argList/argListI.H | 12 + src/OpenFOAM/global/global.Cver | 3 +- src/OpenFOAM/include/OSspecific.H | 5 + 10 files changed, 411 insertions(+), 115 deletions(-) diff --git a/src/OSspecific/MSwindows/MSwindows.C b/src/OSspecific/MSwindows/MSwindows.C index 3be89545c1..5de948e818 100644 --- a/src/OSspecific/MSwindows/MSwindows.C +++ b/src/OSspecific/MSwindows/MSwindows.C @@ -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 libNames, diff --git a/src/OSspecific/POSIX/POSIX.C b/src/OSspecific/POSIX/POSIX.C index 35568ced49..5dadcfea32 100644 --- a/src/OSspecific/POSIX/POSIX.C +++ b/src/OSspecific/POSIX/POSIX.C @@ -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 libNames, diff --git a/src/OpenFOAM/db/Time/Time.C b/src/OpenFOAM/db/Time/Time.C index c215eb6956..644db23f44 100644 --- a/src/OpenFOAM/db/Time/Time.C +++ b/src/OpenFOAM/db/Time/Time.C @@ -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) diff --git a/src/OpenFOAM/db/dynamicLibrary/dlLibraryTable/dlLibraryTable.C b/src/OpenFOAM/db/dynamicLibrary/dlLibraryTable/dlLibraryTable.C index 81c122215c..094fe75e7d 100644 --- a/src/OpenFOAM/db/dynamicLibrary/dlLibraryTable/dlLibraryTable.C +++ b/src/OpenFOAM/db/dynamicLibrary/dlLibraryTable/dlLibraryTable.C @@ -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& 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& 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& 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; } diff --git a/src/OpenFOAM/db/dynamicLibrary/dlLibraryTable/dlLibraryTable.H b/src/OpenFOAM/db/dynamicLibrary/dlLibraryTable/dlLibraryTable.H index 8948910c2d..66f88c2b29 100644 --- a/src/OpenFOAM/db/dynamicLibrary/dlLibraryTable/dlLibraryTable.H +++ b/src/OpenFOAM/db/dynamicLibrary/dlLibraryTable/dlLibraryTable.H @@ -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 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& 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& 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& 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; }; diff --git a/src/OpenFOAM/global/argList/argList.C b/src/OpenFOAM/global/argList/argList.C index 2ac39189fe..157da8b8a8 100644 --- a/src/OpenFOAM/global/argList/argList.C +++ b/src/OpenFOAM/global/argList/argList.C @@ -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(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); } diff --git a/src/OpenFOAM/global/argList/argList.H b/src/OpenFOAM/global/argList/argList.H index 422818c5a2..da9969fdff 100644 --- a/src/OpenFOAM/global/argList/argList.H +++ b/src/OpenFOAM/global/argList/argList.H @@ -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 // Transitional features - older style access (including 1712 release) @@ -142,6 +140,9 @@ class argList //- The extracted options HashTable 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 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 */ - }; diff --git a/src/OpenFOAM/global/argList/argListI.H b/src/OpenFOAM/global/argList/argListI.H index 54e4ac9d8e..bfa5581272 100644 --- a/src/OpenFOAM/global/argList/argListI.H +++ b/src/OpenFOAM/global/argList/argListI.H @@ -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(); diff --git a/src/OpenFOAM/global/global.Cver b/src/OpenFOAM/global/global.Cver index a17064c5fb..40df366763 100644 --- a/src/OpenFOAM/global/global.Cver +++ b/src/OpenFOAM/global/global.Cver @@ -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)) diff --git a/src/OpenFOAM/include/OSspecific.H b/src/OpenFOAM/include/OSspecific.H index 4e9e0ae4c8..02c5512b0d 100644 --- a/src/OpenFOAM/include/OSspecific.H +++ b/src/OpenFOAM/include/OSspecific.H @@ -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)