Loading...
Searching...
No Matches
LammpsLoader.cpp
Go to the documentation of this file.
1/*
2** This file is part of eOn.
3**
4** SPDX-License-Identifier: BSD-3-Clause
5**
6** Copyright (c) 2010--present, eOn Development Team
7** All rights reserved.
8**
9** Repo:
10** https://github.com/TheochemUI/eOn
11*/
13
14#include <cstdlib>
15#include <filesystem>
16#include <iostream>
17#include <string>
18#include <system_error>
19
20namespace eonc {
21
22namespace {
23
24const char *const *lammps_lib_names() noexcept {
25#ifdef _WIN32
26 static const char *names[] = {"lammps.dll", "liblammps.dll", nullptr};
27#elif defined(__APPLE__)
28 static const char *names[] = {"liblammps.dylib", "liblammps.0.dylib",
29 nullptr};
30#else
31 static const char *names[] = {"liblammps.so", "liblammps.so.0", nullptr};
32#endif
33 return names;
34}
35
36bool path_exists(const std::filesystem::path &p) {
37 std::error_code ec;
38 return std::filesystem::exists(p, ec);
39}
40
41bool lib_file_visible(const char *const *names) {
42 for (const char *const *n = names; *n; ++n) {
43 if (path_exists(*n))
44 return true;
45 }
46#ifdef _WIN32
47 const char *path = std::getenv("PATH");
48 const char sep = ';';
49#else
50 const char *path = std::getenv("LD_LIBRARY_PATH");
51#ifdef __APPLE__
52 if (!path || !*path)
53 path = std::getenv("DYLD_LIBRARY_PATH");
54#endif
55 const char sep = ':';
56#endif
57 if (!path || !*path)
58 return false;
59 const std::string paths(path);
60 std::string::size_type start = 0;
61 while (start < paths.size()) {
62 auto pos = paths.find(sep, start);
63 if (pos == std::string::npos)
64 pos = paths.size();
65 if (pos > start) {
66 const std::filesystem::path dir(paths.substr(start, pos - start));
67 for (const char *const *n = names; *n; ++n) {
68 if (path_exists(dir / *n))
69 return true;
70 }
71 }
72 start = pos + 1;
73 }
74 return false;
75}
76
77} // namespace
78
80 static LammpsLoader loader;
81 return loader;
82}
83
85 if (m_tried)
86 return;
87 m_tried = true;
88
89 m_handle = dynlib::openFirst(lammps_lib_names());
90 if (!m_handle) {
91 return;
92 }
93
95 close = dynlib::loadSym<close_fn>(m_handle, "lammps_close");
96 command = dynlib::loadSym<command_fn>(m_handle, "lammps_command");
97 file = dynlib::loadSym<file_fn>(m_handle, "lammps_file");
99 dynlib::loadSym<scatter_atoms_fn>(m_handle, "lammps_scatter_atoms");
101 dynlib::loadSym<extract_var_fn>(m_handle, "lammps_extract_variable");
102
103#ifdef EONMPI
104 open_mpi = dynlib::loadSym<open_mpi_fn>(m_handle, "lammps_open");
105#endif
106
107 if (!open_no_mpi || !close || !command || !file || !scatter_atoms ||
109 std::cerr << "[LAMMPS] Library loaded but missing required symbols\n";
111 m_handle = {};
112 return;
113 }
114
115 m_loaded = true;
116}
117
119
121 return lib_file_visible(lammps_lib_names());
122}
123
126 if (!m_loaded) {
127 throw std::runtime_error(
128 "LAMMPS potential requested but liblammps not found.\n"
129 "Install via: conda install -c conda-forge lammps\n"
130 "Or ensure liblammps is in your library search path "
131 "(LD_LIBRARY_PATH / DYLD_LIBRARY_PATH / PATH).");
132 }
133}
134
135} // namespace eonc
scatter_atoms_fn scatter_atoms
bool available() const
Filesystem probe: a candidate liblammps file is visible without dlopen, so LAMMPS static initializers...
void require_loaded()
Load on first use, then throw if liblammps is not available.
open_no_mpi_fn open_no_mpi
LammpsLoader(const LammpsLoader &)=delete
static LammpsLoader & instance()
Thread-safe singleton accessor (Meyer's pattern). Does not dlopen.
dynlib::Handle m_handle
extract_var_fn extract_variable
void close(Handle h) noexcept
Definition DynLib.h:77
Fn loadSym(Handle h, const char *name) noexcept
Load a symbol and cast to a function pointer type.
Definition DynLib.h:99
Handle openFirst(const char *const names[]) noexcept
Try a list of library names in order, return first successful handle.
Definition DynLib.h:89
RAII resource manager for the ARTn C library with global synchronization.