Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Homogenize finding our components. #1336

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
93 changes: 89 additions & 4 deletions src/config/config.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,27 @@

#include "config/config.h"

#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <sstream>

#if defined(_WIN32)
#include <windows.h>
#elif defined(__APPLE__)
#include <limits.h>
#include <mach-o/dyld.h>
#else
#endif

namespace fs = std::filesystem;

/// Git version of the project
const std::string nmodl::Version::GIT_REVISION = "@NMODL_GIT_REVISION@";

/// NMODL version
const std::string nmodl::Version::NMODL_VERSION = "@PROJECT_VERSION@";

const std::string nmodl::CMakeInfo::SHARED_LIBRARY_SUFFIX = "@CMAKE_SHARED_LIBRARY_SUFFIX@";

/**
* \brief Path of nrnutils.lib file
*
Expand All @@ -23,5 +36,77 @@ const std::string nmodl::CMakeInfo::SHARED_LIBRARY_SUFFIX = "@CMAKE_SHARED_LIBRA
* from CMAKE_INSTALL_PREFIX. Note that this use of NMODL_PROJECT_BINARY_DIR
* will cause ccache misses when the build prefix is changed.
*/
std::vector<std::string> nmodl::NrnUnitsLib::NRNUNITSLIB_PATH =
{"@CMAKE_INSTALL_PREFIX@/share/nmodl/nrnunits.lib", "@NMODL_PROJECT_BINARY_DIR@/share/nmodl/nrnunits.lib"};
const std::vector<std::string> nmodl::PathHelper::BASE_SEARCH_PATHS =
{"@CMAKE_INSTALL_PREFIX@", "@NMODL_PROJECT_BINARY_DIR@"};

const std::string nmodl::PathHelper::SHARED_LIBRARY_PREFIX = "@CMAKE_SHARED_LIBRARY_PREFIX@";
const std::string nmodl::PathHelper::SHARED_LIBRARY_SUFFIX = "@CMAKE_SHARED_LIBRARY_SUFFIX@";

namespace {

std::string maybe_from_env(const std::string& varname) {
const auto value = std::getenv(varname.c_str());
if (value != nullptr) {
return value;
}

#if defined(_WIN32)
std::vector<char> buffer;
DWORD copied = 0;
do {
buffer.resize(buffer.size() + MAX_PATH);
copied = GetModuleFileName(0, &buffer.at(0), buffer.size());
} while (copied >= buffer.size());
buffer.resize(copied);
fs::path executable(std::wstring(buffer.begin(), buffer.end()));
#elif defined(__APPLE__)
char buffer[PATH_MAX + 1];
uint32_t bufsize = PATH_MAX + 1;
if( _NSGetExecutablePath(buffer, &bufsize) != 0) {
return "";
}
auto executable = fs::path(buffer);
#else
auto executable = fs::read_symlink("/proc/self/exe");
#endif

auto executable_dir = fs::weakly_canonical(executable).parent_path();
if (executable_dir.filename() == "bin") {
return executable_dir.parent_path().string();
} else {
// On Windows, we may find ourselves in the top-level directory without a bin/
return executable_dir.string();
}
}

}

const std::string nmodl::PathHelper::NMODL_HOME = maybe_from_env("NMODL_HOME");

std::string nmodl::PathHelper::get_path(const std::string& what, bool is_library) {
std::vector<std::string> search_paths = BASE_SEARCH_PATHS;
if (!NMODL_HOME.empty()) {
search_paths.emplace(search_paths.begin(), NMODL_HOME);
}

// check paths in order and return if found
for (const auto& path: search_paths) {
auto full_path = fs::path(path);
if (is_library) {
full_path /= SHARED_LIBRARY_PREFIX + what + SHARED_LIBRARY_SUFFIX;
} else {
full_path /= what;
}
std::ifstream f(full_path);
if (f.good()) {
return full_path;
}
}
std::ostringstream err_msg;
err_msg << "Could not find '" << what << "' in any of:\n";
for (const auto& path: search_paths) {
err_msg << "\t" << path << "\n";
}
err_msg << "Please try setting the NMODLHOME environment variable\n";
throw std::runtime_error(err_msg.str());
}
57 changes: 27 additions & 30 deletions src/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
* \brief Version information and units file path
*/

#include <cstdlib>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

Expand All @@ -44,38 +41,38 @@
/**
* \brief Information of units database i.e. `nrnunits.lib`
*/
struct NrnUnitsLib {
/// paths where nrnunits.lib can be found
static std::vector<std::string> NRNUNITSLIB_PATH;
class PathHelper {
/// pre-defined paths to search for files
const static std::vector<std::string> BASE_SEARCH_PATHS;

/// prefix to use when looking for libraries
const static std::string SHARED_LIBRARY_PREFIX;

/// suffix to use when looking for libraries
const static std::string SHARED_LIBRARY_SUFFIX;

/// base directory of the NMODL installation
const static std::string NMODL_HOME;

/**
* Search for a given relative file path
*/
static std::string get_path(const std::string& what, bool is_library = false);

public:
/**
* Return path of units database file
*/
static std::string get_path() {
// first look for NMODLHOME env variable
if (const char* nmodl_home = std::getenv("NMODLHOME")) {
auto path = std::string(nmodl_home) + "/share/nmodl/nrnunits.lib";
NRNUNITSLIB_PATH.emplace(NRNUNITSLIB_PATH.begin(), path);
}

// check paths in order and return if found
for (const auto& path: NRNUNITSLIB_PATH) {
std::ifstream f(path.c_str());
if (f.good()) {
return path;
}
}
std::ostringstream err_msg;
err_msg << "Could not find nrnunits.lib in any of:\n";
for (const auto& path: NRNUNITSLIB_PATH) {
err_msg << path << "\n";
}
throw std::runtime_error(err_msg.str());
}
};
static std::string get_units_path() {
return get_path("share/nmodl/nrnunits.lib");
};

struct CMakeInfo {
static const std::string SHARED_LIBRARY_SUFFIX;
/**
* Return path of the python wrapper library
*/
static std::string get_wrapper_path() {
return get_path("lib/libpywrapper", true);

Check warning on line 74 in src/config/config.h

View check run for this annotation

Codecov / codecov/patch

src/config/config.h#L73-L74

Added lines #L73 - L74 were not covered by tests
};
};

} // namespace nmodl
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ int main(int argc, const char* argv[]) {
std::string scratch_dir("tmp");

/// directory where units lib file is located
std::string units_dir(NrnUnitsLib::get_path());
std::string units_dir(PathHelper::get_units_path());

/// true if ast should be converted to json
bool json_ast(false);
Expand Down
2 changes: 1 addition & 1 deletion src/parser/main_units.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
fmt::format("Unit-Parser : Standalone Parser for Units({})", Version::to_string())};

std::vector<std::string> units_files;
units_files.push_back(NrnUnitsLib::get_path());
units_files.push_back(PathHelper::get_units_path());

Check warning on line 31 in src/parser/main_units.cpp

View check run for this annotation

Codecov / codecov/patch

src/parser/main_units.cpp#L31

Added line #L31 was not covered by tests
app.add_option("units_files", units_files, "One or more Units files to process");

CLI11_PARSE(app, argc, argv);
Expand Down
17 changes: 3 additions & 14 deletions src/pybind/pyembed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,22 +81,11 @@

assert_compatible_python_versions();

if (std::getenv("NMODLHOME") == nullptr) {
logger->critical("NMODLHOME environment variable must be set to load embedded python");
throw std::runtime_error("NMODLHOME not set");
}
auto pybind_wraplib_env = fs::path(std::getenv("NMODLHOME")) / "lib" / "libpywrapper";
pybind_wraplib_env.concat(CMakeInfo::SHARED_LIBRARY_SUFFIX);
if (!fs::exists(pybind_wraplib_env)) {
logger->critical("NMODLHOME doesn't contain libpywrapper{} library",
CMakeInfo::SHARED_LIBRARY_SUFFIX);
throw std::runtime_error("NMODLHOME doesn't have lib/libpywrapper library");
}
std::string env_str = pybind_wraplib_env.string();
pybind_wrapper_handle = dlopen(env_str.c_str(), dlopen_opts);
auto pybind_wraplib_env = PathHelper::get_wrapper_path();
pybind_wrapper_handle = dlopen(pybind_wraplib_env.c_str(), dlopen_opts);

Check warning on line 85 in src/pybind/pyembed.cpp

View check run for this annotation

Codecov / codecov/patch

src/pybind/pyembed.cpp#L84-L85

Added lines #L84 - L85 were not covered by tests
if (!pybind_wrapper_handle) {
const auto errstr = dlerror();
logger->critical("Tried but failed to load {}", pybind_wraplib_env.string());
logger->critical("Tried but failed to load {}", pybind_wraplib_env);

Check warning on line 88 in src/pybind/pyembed.cpp

View check run for this annotation

Codecov / codecov/patch

src/pybind/pyembed.cpp#L88

Added line #L88 was not covered by tests
logger->critical(errstr);
throw std::runtime_error("Failed to dlopen");
}
Expand Down
2 changes: 1 addition & 1 deletion src/visitors/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
"SympyConductanceVisitor"},
{std::make_shared<SympySolverVisitor>(), "sympy-solve", "SympySolverVisitor"},
{std::make_shared<NeuronSolveVisitor>(), "neuron-solve", "NeuronSolveVisitor"},
{std::make_shared<UnitsVisitor>(NrnUnitsLib::get_path()), "units", "UnitsVisitor"},
{std::make_shared<UnitsVisitor>(PathHelper::get_units_path()), "units", "UnitsVisitor"},

Check warning on line 98 in src/visitors/main.cpp

View check run for this annotation

Codecov / codecov/patch

src/visitors/main.cpp#L98

Added line #L98 was not covered by tests
};

const std::vector<ConstVisitorInfo> const_visitors = {
Expand Down
2 changes: 1 addition & 1 deletion test/unit/units/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ bool is_valid_construct(const std::string& construct) {

std::string parse_string(const std::string& unit_definition) {
nmodl::parser::UnitDriver correctness_driver;
correctness_driver.parse_file(nmodl::NrnUnitsLib::get_path());
correctness_driver.parse_file(nmodl::PathHelper::get_units_path());
correctness_driver.parse_string(unit_definition);
std::stringstream ss;
correctness_driver.table->print_units_sorted(ss);
Expand Down
2 changes: 1 addition & 1 deletion test/unit/visitor/units.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ std::tuple<std::shared_ptr<ast::Program>, std::shared_ptr<units::UnitTable>> run
const auto& ast = driver.get_ast();

// Parse nrnunits.lib file and the UNITS block of the mod file
const std::string units_lib_path(NrnUnitsLib::get_path());
const std::string units_lib_path(PathHelper::get_units_path());
UnitsVisitor units_visitor = UnitsVisitor(units_lib_path);

units_visitor.visit_program(*ast);
Expand Down
Loading