From 6dd501c62a2c946378ed7fa3a73492b1180760b5 Mon Sep 17 00:00:00 2001 From: Teemu Murtola Date: Thu, 1 Jan 2015 08:28:29 +0200 Subject: [PATCH] Refactor logic for finding share/top/ files Refactor the logic of how gmxlibfn() finds the library files into a separate C++ class that provides some support for customization. By itself, this change only rewrites the existing logic into C++ with a few minor functional changes: - unit tests no longer get confused if GMXLIB is set, and - the default data directory is searched even if GMXLIB is set, removing the need to duplicate all the files into custom directories and/or to manually specify the default directory. However, it also lays the groundwork for further refactoring: - consolidating the other direct use of GMXLIB env.var. from fflibutil.cpp into the same place - more reusable logic for finding the files, e.g., for JIT compilation or for structuring the data files into more than one directory - removing one-off uses of functions like low_libopen Change-Id: I4e14a7e7f11846b3828265c1c735da6bc57f97ff --- src/gromacs/commandline/cmdlineinit.cpp | 11 +- src/gromacs/utility/CMakeLists.txt | 3 +- src/gromacs/utility/datafilefinder.cpp | 198 ++++++++++++++++++++++++ src/gromacs/utility/datafilefinder.h | 196 +++++++++++++++++++++++ src/gromacs/utility/file.cpp | 29 +++- src/gromacs/utility/file.h | 15 +- src/gromacs/utility/futil.cpp | 109 ++++++------- src/gromacs/utility/futil.h | 46 +++++- src/testutils/testinit.cpp | 4 + 9 files changed, 534 insertions(+), 77 deletions(-) create mode 100644 src/gromacs/utility/datafilefinder.cpp create mode 100644 src/gromacs/utility/datafilefinder.h diff --git a/src/gromacs/commandline/cmdlineinit.cpp b/src/gromacs/commandline/cmdlineinit.cpp index a7d23b3755..49786a1033 100644 --- a/src/gromacs/commandline/cmdlineinit.cpp +++ b/src/gromacs/commandline/cmdlineinit.cpp @@ -1,7 +1,7 @@ /* * This file is part of the GROMACS molecular simulation package. * - * Copyright (c) 2013,2014, by the GROMACS development team, led by + * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -54,7 +54,9 @@ #include "gromacs/commandline/cmdlineprogramcontext.h" #include "gromacs/legacyheaders/network.h" #include "gromacs/legacyheaders/types/commrec.h" +#include "gromacs/utility/datafilefinder.h" #include "gromacs/utility/exceptions.h" +#include "gromacs/utility/futil.h" #include "gromacs/utility/gmxassert.h" #include "gromacs/utility/init.h" #include "gromacs/utility/programcontext.h" @@ -71,6 +73,8 @@ namespace //! Global context instance initialized in initForCommandLine(). boost::scoped_ptr g_commandLineContext; +//! Global library data file finder that respects GMXLIB. +boost::scoped_ptr g_libFileFinder; #ifdef GMX_LIB_MPI void broadcastArguments(const t_commrec *cr, int *argc, char ***argv) @@ -125,6 +129,9 @@ CommandLineProgramContext &initForCommandLine(int *argc, char ***argv) { g_commandLineContext.reset(new CommandLineProgramContext(*argc, *argv)); setProgramContext(g_commandLineContext.get()); + g_libFileFinder.reset(new DataFileFinder()); + g_libFileFinder->setSearchPathFromEnv("GMXLIB"); + setLibraryFileFinder(g_libFileFinder.get()); } catch (const std::exception &ex) { @@ -137,6 +144,8 @@ CommandLineProgramContext &initForCommandLine(int *argc, char ***argv) void finalizeForCommandLine() { gmx::finalize(); + setLibraryFileFinder(NULL); + g_libFileFinder.reset(); setProgramContext(NULL); g_commandLineContext.reset(); } diff --git a/src/gromacs/utility/CMakeLists.txt b/src/gromacs/utility/CMakeLists.txt index d1abc0659c..88a0c2678d 100644 --- a/src/gromacs/utility/CMakeLists.txt +++ b/src/gromacs/utility/CMakeLists.txt @@ -1,7 +1,7 @@ # # This file is part of the GROMACS molecular simulation package. # -# Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by +# Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, # and including many others, as listed in the AUTHORS file in the # top-level source directory and at http://www.gromacs.org. @@ -40,6 +40,7 @@ gmx_install_headers( basedefinitions.h classhelpers.h cstringutil.h + datafilefinder.h errorcodes.h exceptions.h fatalerror.h diff --git a/src/gromacs/utility/datafilefinder.cpp b/src/gromacs/utility/datafilefinder.cpp new file mode 100644 index 0000000000..da1e3e0e3b --- /dev/null +++ b/src/gromacs/utility/datafilefinder.cpp @@ -0,0 +1,198 @@ +/* + * This file is part of the GROMACS molecular simulation package. + * + * Copyright (c) 2014,2015, by the GROMACS development team, led by + * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, + * and including many others, as listed in the AUTHORS file in the + * top-level source directory and at http://www.gromacs.org. + * + * GROMACS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * GROMACS 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with GROMACS; if not, see + * http://www.gnu.org/licenses, or write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * If you want to redistribute modifications to GROMACS, please + * consider that scientific software is very special. Version + * control is crucial - bugs must be traceable. We will be happy to + * consider code for inclusion in the official distribution, but + * derived work must not be called official GROMACS. Details are found + * in the README & COPYING files - if they are missing, get the + * official version at http://www.gromacs.org. + * + * To help us fund GROMACS development, we humbly ask that you cite + * the research papers on the package. Check out http://www.gromacs.org. + */ +/*! \internal \file + * \brief + * Implements gmx::DataFileFinder. + * + * \author Teemu Murtola + * \ingroup module_utility + */ +#include "gmxpre.h" + +#include "datafilefinder.h" + +#include + +#include +#include + +#include "gromacs/utility/exceptions.h" +#include "gromacs/utility/file.h" +#include "gromacs/utility/path.h" +#include "gromacs/utility/programcontext.h" +#include "gromacs/utility/stringutil.h" + +namespace gmx +{ + +/******************************************************************** + * DataFileFinder::Impl + */ + +class DataFileFinder::Impl +{ + public: + Impl() : envName_(NULL), bEnvIsSet_(false) {} + + const char *envName_; + bool bEnvIsSet_; + std::vector searchPath_; +}; + +/******************************************************************** + * DataFileFinder + */ + +DataFileFinder::DataFileFinder() + : impl_(NULL) +{ +} + +DataFileFinder::~DataFileFinder() +{ +} + +void DataFileFinder::setSearchPathFromEnv(const char *envVarName) +{ + if (!impl_.get()) + { + impl_.reset(new Impl()); + } + impl_->envName_ = envVarName; + const char *const lib = getenv(envVarName); + if (lib != NULL) + { + impl_->bEnvIsSet_ = true; + Path::splitPathEnvironment(lib, &impl_->searchPath_); + } +} + +FILE *DataFileFinder::openFile(const DataFileOptions &options) const +{ + // TODO: There is a small race here, since there is some time between + // the exists() calls and actually opening the file. It would be better + // to leave the file open after a successful exists() if the desire is to + // actually open the file. + std::string filename = findFile(options); + if (filename.empty()) + { + return NULL; + } +#if 0 + if (debug) + { + fprintf(debug, "Opening library file %s\n", fn); + } +#endif + return File::openRawHandle(filename, "r"); +} + +std::string DataFileFinder::findFile(const DataFileOptions &options) const +{ + if (options.bCurrentDir_ && Path::exists(options.filename_)) + { + return options.filename_; + } + if (impl_.get()) + { + std::vector::const_iterator i; + for (i = impl_->searchPath_.begin(); i != impl_->searchPath_.end(); ++i) + { + // TODO: Deal with an empty search path entry more reasonably. + std::string testPath = Path::join(*i, options.filename_); + // TODO: Consider skipping directories. + if (Path::exists(testPath)) + { + return testPath; + } + } + } + const char *const defaultPath = getProgramContext().defaultLibraryDataPath(); + if (defaultPath != NULL && defaultPath[0] != '\0') + { + std::string testPath = Path::join(defaultPath, options.filename_); + if (Path::exists(testPath)) + { + return testPath; + } + } + if (options.bThrow_) + { + const char *const envName = (impl_.get() ? impl_->envName_ : NULL); + const bool bEnvIsSet = (impl_.get() ? impl_->bEnvIsSet_ : false); + std::string message( + formatString("Library file %s not found", options.filename_)); + if (options.bCurrentDir_) + { + message.append(" in current dir nor"); + } + if (bEnvIsSet) + { + message.append(formatString(" in your %s path nor", envName)); + } + message.append(" in the default directories.\nThe following paths were searched:"); + if (options.bCurrentDir_) + { + message.append("\n "); + message.append(Path::getWorkingDirectory()); + message.append(" (current dir)"); + } + if (impl_.get()) + { + std::vector::const_iterator i; + for (i = impl_->searchPath_.begin(); i != impl_->searchPath_.end(); ++i) + { + message.append("\n "); + message.append(*i); + } + } + if (defaultPath != NULL && defaultPath[0] != '\0') + { + message.append("\n "); + message.append(defaultPath); + message.append(" (default)"); + } + if (!bEnvIsSet && envName != NULL) + { + message.append( + formatString("\nYou can set additional directories to search " + "with the %s path variable.", envName)); + } + GMX_THROW(FileIOError(message)); + } + return std::string(); +} + +} // namespace gmx diff --git a/src/gromacs/utility/datafilefinder.h b/src/gromacs/utility/datafilefinder.h new file mode 100644 index 0000000000..383ccfb7ea --- /dev/null +++ b/src/gromacs/utility/datafilefinder.h @@ -0,0 +1,196 @@ +/* + * This file is part of the GROMACS molecular simulation package. + * + * Copyright (c) 2014,2015, by the GROMACS development team, led by + * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, + * and including many others, as listed in the AUTHORS file in the + * top-level source directory and at http://www.gromacs.org. + * + * GROMACS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * GROMACS 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with GROMACS; if not, see + * http://www.gnu.org/licenses, or write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * If you want to redistribute modifications to GROMACS, please + * consider that scientific software is very special. Version + * control is crucial - bugs must be traceable. We will be happy to + * consider code for inclusion in the official distribution, but + * derived work must not be called official GROMACS. Details are found + * in the README & COPYING files - if they are missing, get the + * official version at http://www.gromacs.org. + * + * To help us fund GROMACS development, we humbly ask that you cite + * the research papers on the package. Check out http://www.gromacs.org. + */ +/*! \file + * \brief + * Declares gmx::DataFileFinder and related classes. + * + * \author Teemu Murtola + * \inpublicapi + * \ingroup module_utility + */ +#ifndef GMX_UTILITY_LIBFILEFINDER_H +#define GMX_UTILITY_LIBFILEFINDER_H + +#include + +#include + +#include "gromacs/utility/classhelpers.h" + +namespace gmx +{ + +class DataFileFinder; + +/*! \brief + * Search parameters for DataFileFinder. + * + * This class implements a named parameter idiom for DataFileFinder::findFile() + * and DataFileFinder::openFile() to support an easily readable and + * customizable way of searching data files. + * + * By default, the search first considers the current directory, followed by + * specified and default data directories, and an exception is thrown if the + * file could not be found. + * To skip searching in the current directory, use includeCurrentDir(). + * + * Methods in this class do not throw. + * + * \inpublicapi + * \ingroup module_utility + */ +class DataFileOptions +{ + public: + /*! \brief + * Constructs default options for searching for a file with the + * specified name. + * + * \param[in] filename File name to search for. + * + * This constructor is not explicit to allow passing a simple string to + * DataFileFinder methods to search for the string with the default + * parameters. + */ + DataFileOptions(const char *filename) + : filename_(filename), bCurrentDir_(true), bThrow_(true) + { + } + //! \copydoc DataFileOptions(const char *) + DataFileOptions(const std::string &filename) + : filename_(filename.c_str()), bCurrentDir_(true), bThrow_(true) + { + } + + //! Sets whether to search in the current (working) directory. + DataFileOptions &includeCurrentDir(bool bInclude) + { + bCurrentDir_ = bInclude; + return *this; + } + //! Sets whether an exception is thrown if the file could not be found. + DataFileOptions &throwIfNotFound(bool bThrow) + { + bThrow_ = bThrow; + return *this; + } + + private: + const char *filename_; + bool bCurrentDir_; + bool bThrow_; + + /*! \brief + * Needed to access the members without otherwise unnecessary accessors. + */ + friend class DataFileFinder; +}; + +/*! \brief + * Searches data files from a set of paths. + * + * \inpublicapi + * \ingroup module_utility + */ +class DataFileFinder +{ + public: + /*! \brief + * Constructs a default data file finder. + * + * The constructed finder searches only in the directory specified by + * the global program context (see ProgramContextInterface), and + * optionally in the current directory. + * + * Does not throw. + */ + DataFileFinder(); + ~DataFileFinder(); + + /*! \brief + * Adds search path from an environment variable. + * + * \param[in] envVarName Name of the environment variable to use. + * \throws std::bad_alloc if out of memory. + * + * If the specified environment variable is set, it is interpreted like + * a `PATH` environment variable on the platform (split at appropriate + * separators), and each path found is added to the search path this + * finder searches. The added paths take precedence over the default + * directory specified by the global program context, but the current + * directory is searched first. + */ + void setSearchPathFromEnv(const char *envVarName); + + /*! \brief + * Opens a data file if found. + * + * \param[in] options Identifies the file to be searched for. + * \returns The opened file handle, or `NULL` if the file could not be + * found and exceptions were turned off. + * \throws FileIOError if + * - no such file can be found, and \p options specifies that an + * exception should be thrown, or + * - there is an error opening the file (note that a file is skipped + * during the search if the user does not have rights to open the + * file at all). + * + * See findFile() for more details. + */ + FILE *openFile(const DataFileOptions &options) const; + /*! \brief + * Finds a full path to a data file if found. + * + * \param[in] options Identifies the file to be searched for. + * \returns Full path to the data file, or an empty string if the file + * could not be found and exceptions were turned off. + * \throws FileIOError if no such file can be found, and \p options + * specifies that an exception should be thrown. + * + * Searches for a data file in the search paths configured for the + * finder, as well as in the current directory if so required. + * Returns the full path to the first file found. + */ + std::string findFile(const DataFileOptions &options) const; + + private: + class Impl; + + PrivateImplPointer impl_; +}; + +} // namespace gmx + +#endif diff --git a/src/gromacs/utility/file.cpp b/src/gromacs/utility/file.cpp index a194992bfd..dbd809c38b 100644 --- a/src/gromacs/utility/file.cpp +++ b/src/gromacs/utility/file.cpp @@ -1,7 +1,7 @@ /* * This file is part of the GROMACS molecular simulation package. * - * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by + * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -109,6 +109,25 @@ File::Impl::~Impl() } } +// static +FILE *File::openRawHandle(const char *filename, const char *mode) +{ + FILE *fp = fopen(filename, mode); + if (fp == NULL) + { + GMX_THROW_WITH_ERRNO( + FileIOError(formatString("Could not open file '%s'", filename)), + "fopen", errno); + } + return fp; +} + +// static +FILE *File::openRawHandle(const std::string &filename, const char *mode) +{ + return openRawHandle(filename.c_str(), mode); +} + File::File(const char *filename, const char *mode) : impl_(new Impl(NULL, true)) { @@ -135,13 +154,7 @@ void File::open(const char *filename, const char *mode) GMX_RELEASE_ASSERT(impl_->fp_ == NULL, "Attempted to open the same file object twice"); // TODO: Port all necessary functionality from gmx_ffopen() here. - impl_->fp_ = fopen(filename, mode); - if (impl_->fp_ == NULL) - { - GMX_THROW_WITH_ERRNO( - FileIOError(formatString("Could not open file '%s'", filename)), - "fopen", errno); - } + impl_->fp_ = openRawHandle(filename, mode); } void File::open(const std::string &filename, const char *mode) diff --git a/src/gromacs/utility/file.h b/src/gromacs/utility/file.h index 37a55cb03c..d1f354c9a4 100644 --- a/src/gromacs/utility/file.h +++ b/src/gromacs/utility/file.h @@ -1,7 +1,7 @@ /* * This file is part of the GROMACS molecular simulation package. * - * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by + * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -64,6 +64,19 @@ namespace gmx class File { public: + /*! \brief + * Opens a file and returns a `FILE` handle. + * + * \param[in] filename Path of the file to open. + * \param[in] mode Mode to open the file in (for fopen()). + * \throws FileIOError on any I/O error. + * + * Instead of returning `NULL` on errors, throws an exception with + * additional details (including the file name and `errno`). + */ + static FILE *openRawHandle(const char *filename, const char *mode); + //! \copydoc openRawHandle(const char *, const char *) + static FILE *openRawHandle(const std::string &filename, const char *mode); /*! \brief * Creates a file object and opens a file. * diff --git a/src/gromacs/utility/futil.cpp b/src/gromacs/utility/futil.cpp index 9e464ea1a2..6a45173cd4 100644 --- a/src/gromacs/utility/futil.cpp +++ b/src/gromacs/utility/futil.cpp @@ -3,7 +3,7 @@ * * Copyright (c) 1991-2000, University of Groningen, The Netherlands. * Copyright (c) 2001-2004, The GROMACS development team. - * Copyright (c) 2013,2014, by the GROMACS development team, led by + * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -64,6 +64,7 @@ #include "thread_mpi/threads.h" #include "gromacs/utility/cstringutil.h" +#include "gromacs/utility/datafilefinder.h" #include "gromacs/utility/exceptions.h" #include "gromacs/utility/fatalerror.h" #include "gromacs/utility/path.h" @@ -88,6 +89,32 @@ static int s_maxBackupCount = 0; to protect it with mutexes */ static tMPI_Thread_mutex_t pstack_mutex = TMPI_THREAD_MUTEX_INITIALIZER; +namespace gmx +{ +namespace +{ +//! Global library file finder; stores the object set with setLibraryFileFinder(). +const DataFileFinder *g_libFileFinder; +//! Default library file finder if nothing is set. +const DataFileFinder g_defaultLibFileFinder; +} // namespace + +const DataFileFinder &getLibraryFileFinder() +{ + if (g_libFileFinder != NULL) + { + return *g_libFileFinder; + } + return g_defaultLibFileFinder; +} + +void setLibraryFileFinder(const DataFileFinder *finder) +{ + g_libFileFinder = finder; +} + +} // namespace gmx + void gmx_disable_file_buffering(void) { bUnbuffered = true; @@ -689,83 +716,35 @@ gmx_directory_close(gmx_directory_t gmxdir) char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal) { - bool bEnvIsSet = false; try { - if (bAddCWD && gmx_fexist(file)) + const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder(); + std::string result = + finder.findFile(gmx::DataFileOptions(file) + .includeCurrentDir(bAddCWD) + .throwIfNotFound(bFatal)); + if (!result.empty()) { - return gmx_strdup(file); - } - else - { - std::string libpath; - // GMXLIB can be a path. - const char *lib = getenv("GMXLIB"); - if (lib != NULL) - { - bEnvIsSet = true; - libpath = lib; - } - else - { - libpath = gmx::getProgramContext().defaultLibraryDataPath(); - } - - std::vector pathEntries; - gmx::Path::splitPathEnvironment(libpath, &pathEntries); - std::vector::const_iterator i; - for (i = pathEntries.begin(); i != pathEntries.end(); ++i) - { - std::string testPath = gmx::Path::join(*i, file); - if (gmx::Path::exists(testPath)) - { - return gmx_strdup(testPath.c_str()); - } - } + return gmx_strdup(result.c_str()); } } GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR; - if (bFatal) - { - if (bEnvIsSet) - { - gmx_fatal(FARGS, - "Library file %s not found %sin your GMXLIB path.", - file, bAddCWD ? "in current dir nor " : ""); - } - else - { - gmx_fatal(FARGS, - "Library file %s not found %sin default directories.\n" - "(You can set the directories to search with the GMXLIB path variable)", - file, bAddCWD ? "in current dir nor " : ""); - } - } return NULL; } FILE *low_libopen(const char *file, gmx_bool bFatal) { - FILE *ff; - char *fn; - - fn = low_gmxlibfn(file, TRUE, bFatal); - - if (fn == NULL) - { - ff = NULL; - } - else + try { - if (debug) - { - fprintf(debug, "Opening library file %s\n", fn); - } - ff = fopen(fn, "r"); + const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder(); + FILE *fp = + finder.openFile(gmx::DataFileOptions(file) + .includeCurrentDir(true) + .throwIfNotFound(bFatal)); + return fp; } - sfree(fn); - - return ff; + GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR; + return NULL; } char *gmxlibfn(const char *file) diff --git a/src/gromacs/utility/futil.h b/src/gromacs/utility/futil.h index c536858609..0b5c1eeadf 100644 --- a/src/gromacs/utility/futil.h +++ b/src/gromacs/utility/futil.h @@ -3,7 +3,7 @@ * * Copyright (c) 1991-2000, University of Groningen, The Netherlands. * Copyright (c) 2001-2004, The GROMACS development team. - * Copyright (c) 2013,2014, by the GROMACS development team, led by + * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -269,6 +269,50 @@ void gmx_getcwd(char *buffer, size_t size); #ifdef __cplusplus } + +namespace gmx +{ + +class DataFileFinder; + +/*! \brief + * Gets a finder for locating data files from share/top/. + * + * \returns Finder set with setLibraryFileFinder(), or a default finder. + * + * If setLibraryFileFinder() has not been called (or a `NULL` finder has been + * set), a default finder is returned. + * The default finder searches data files from the directory identified by the + * global program context; it does not respect GMXLIB environment variable. + * Calling initForCommandLine() sets a finder that respects GMXLIB. + * + * Does not throw. + * + * See setLibraryFileFinder() for thread safety. + * + * \ingroup module_utility + */ +const DataFileFinder &getLibraryFileFinder(); +/*! \brief + * Sets a finder for location data files from share/top/. + * + * \param[in] finder finder to set + * (can be NULL to restore the default finder). + * + * The library does not take ownership of \p finder. + * The provided object must remain valid until the global instance is changed + * by another call to setLibraryFileFinder(). + * + * The global instance is used by gmxlibfn() and libopen(). + * + * This method is not thread-safe. See setProgramContext(); the same + * constraints apply here as well. + * + * Does not throw. + */ +void setLibraryFileFinder(const DataFileFinder *finder); + +} // namespace gmx #endif #endif diff --git a/src/testutils/testinit.cpp b/src/testutils/testinit.cpp index 20e5f2eaae..8bf66f88c1 100644 --- a/src/testutils/testinit.cpp +++ b/src/testutils/testinit.cpp @@ -62,6 +62,7 @@ #include "gromacs/utility/errorcodes.h" #include "gromacs/utility/exceptions.h" #include "gromacs/utility/file.h" +#include "gromacs/utility/futil.h" #include "gromacs/utility/path.h" #include "gromacs/utility/programcontext.h" @@ -164,6 +165,9 @@ void initTestUtils(const char *dataPath, const char *tempPath, int *argc, char * { g_testContext.reset(new TestProgramContext(context)); setProgramContext(g_testContext.get()); + // Use the default finder that does not respect GMXLIB, since the tests + // generally can only get confused by a different set of data files. + setLibraryFileFinder(NULL); ::testing::InitGoogleMock(argc, *argv); if (dataPath != NULL) { -- 2.22.0