* \brief
* Implements gmx::CommandLineProgramContext.
*
+ * See \linktodevmanual{relocatable-binaries,developer guide section on
+ * relocatable binaries} for explanation of the searching logic.
+ *
* \author Teemu Murtola <teemu.murtola@gmail.com>
* \ingroup module_commandline
*/
+#include "gmxpre.h"
+
#include "cmdlineprogramcontext.h"
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <cstdlib>
#include <cstring>
#include "thread_mpi/mutex.h"
-#include "gromacs/fileio/path.h"
+#include "buildinfo.h"
#include "gromacs/utility/exceptions.h"
-#include "gromacs/utility/file.h"
#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/path.h"
#include "gromacs/utility/stringutil.h"
namespace gmx
* Returns whether given path prefix contains files from `share/top/`.
*
* \param[in] path Path prefix to check.
- * \param[out] result If return value is `true`, the pointee is set to the
- * actual data directory. Otherwise, the pointee is not modified.
* \returns `true` if \p path contains the data files.
*
* Checks whether \p path could be the installation prefix where `share/top/`
* files have been installed: appends the relative installation path of the
* data files and calls isAcceptableLibraryPath().
*/
-bool isAcceptableLibraryPathPrefix(const std::string &path, std::string *result)
+bool isAcceptableLibraryPathPrefix(const std::string &path)
{
- std::string testPath = Path::join(path, GMXLIB_SEARCH_DIR);
+ std::string testPath = Path::join(path, DATA_INSTALL_DIR, "top");
if (isAcceptableLibraryPath(testPath))
{
- *result = testPath;
return true;
}
return false;
}
/*! \brief
- * Returns a fallback data path.
+ * Returns a fallback installation prefix path.
*
* Checks a few standard locations for the data files before returning a
* configure-time hard-coded path. The hard-coded path is preferred if it
* actually contains the data files, though.
*/
-std::string findFallbackLibraryDataPath()
+std::string findFallbackInstallationPrefixPath()
{
#ifndef GMX_NATIVE_WINDOWS
- if (!isAcceptableLibraryPath(GMXLIB_FALLBACK))
+ if (!isAcceptableLibraryPathPrefix(CMAKE_INSTALL_PREFIX))
{
- std::string foundPath;
- if (isAcceptableLibraryPathPrefix("/usr/local", &foundPath))
+ if (isAcceptableLibraryPathPrefix("/usr/local"))
{
- return foundPath;
+ return "/usr/local";
}
- if (isAcceptableLibraryPathPrefix("/usr", &foundPath))
+ if (isAcceptableLibraryPathPrefix("/usr"))
{
- return foundPath;
+ return "/usr";
}
- if (isAcceptableLibraryPathPrefix("/opt", &foundPath))
+ if (isAcceptableLibraryPathPrefix("/opt"))
{
- return foundPath;
+ return "/opt";
}
}
#endif
- return GMXLIB_FALLBACK;
+ return CMAKE_INSTALL_PREFIX;
}
/*! \brief
- * Finds the library data files based on path of the binary.
+ * Generic function to find data files based on path of the binary.
*
- * \param[in] binaryPath Absolute path to the binary.
+ * \param[in] binaryPath Absolute path to the binary.
+ * \param[out] bSourceLayout Set to `true` if the binary is run from
+ * the build tree and the original source directory can be found.
* \returns Path to the `share/top/` data files.
*
* The search based on the path only works if the binary is in the same
* Extra logic is present to allow running binaries from the build tree such
* that they use up-to-date data files from the source tree.
*/
-std::string findDefaultLibraryDataPath(const std::string &binaryPath)
+std::string findInstallationPrefixPath(const std::string &binaryPath,
+ bool *bSourceLayout)
{
- // If the input path is not absolute, the binary could not be found.
- // Don't search anything.
- if (Path::isAbsolute(binaryPath))
+ *bSourceLayout = false;
+ // Don't search anything if binary cannot be found.
+ if (Path::exists(binaryPath))
{
// Remove the executable name.
std::string searchPath = Path::getParentPath(binaryPath);
std::string testPath = Path::join(CMAKE_SOURCE_DIR, "share/top");
if (isAcceptableLibraryPath(testPath))
{
- return testPath;
+ *bSourceLayout = true;
+ return CMAKE_SOURCE_DIR;
}
}
#endif
// Use the executable path to (try to) find the library dir.
+ // TODO: Consider only going up exactly the required number of levels.
while (!searchPath.empty())
{
- std::string testPath = Path::join(searchPath, GMXLIB_SEARCH_DIR);
- if (isAcceptableLibraryPath(testPath))
+ if (isAcceptableLibraryPathPrefix(searchPath))
{
- return testPath;
+ return searchPath;
}
searchPath = Path::getParentPath(searchPath);
}
// End of smart searching. If we didn't find it in our parent tree,
// or if the program name wasn't set, return a fallback.
- return findFallbackLibraryDataPath();
+ return findFallbackInstallationPrefixPath();
}
//! \}
std::string displayName_;
std::string commandLine_;
mutable std::string fullBinaryPath_;
- mutable std::string defaultLibraryDataPath_;
+ mutable std::string installationPrefix_;
+ mutable bool bSourceLayout_;
mutable tMPI::mutex binaryPathMutex_;
};
CommandLineProgramContext::Impl::Impl()
- : programName_("GROMACS")
+ : programName_("GROMACS"), bSourceLayout_(false)
{
}
CommandLineProgramContext::Impl::Impl(int argc, const char *const argv[],
ExecutableEnvironmentPointer env)
- : executableEnv_(move(env))
+ : executableEnv_(env), bSourceLayout_(false)
{
invokedName_ = (argc != 0 ? argv[0] : "");
programName_ = Path::getFilename(invokedName_);
CommandLineProgramContext::CommandLineProgramContext(
int argc, const char *const argv[], ExecutableEnvironmentPointer env)
- : impl_(new Impl(argc, argv, move(env)))
+ : impl_(new Impl(argc, argv, env))
{
}
return impl_->fullBinaryPath_.c_str();
}
-const char *CommandLineProgramContext::defaultLibraryDataPath() const
+InstallationPrefixInfo CommandLineProgramContext::installationPrefix() const
{
tMPI::lock_guard<tMPI::mutex> lock(impl_->binaryPathMutex_);
- if (impl_->defaultLibraryDataPath_.empty())
+ if (impl_->installationPrefix_.empty())
{
impl_->findBinaryPath();
- impl_->defaultLibraryDataPath_ =
- Path::normalize(findDefaultLibraryDataPath(impl_->fullBinaryPath_));
+ impl_->installationPrefix_ =
+ Path::normalize(findInstallationPrefixPath(impl_->fullBinaryPath_,
+ &impl_->bSourceLayout_));
}
- return impl_->defaultLibraryDataPath_.c_str();
+ return InstallationPrefixInfo(
+ impl_->installationPrefix_.c_str(),
+ impl_->bSourceLayout_);
}
} // namespace gmx