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

Test separately built catalogues #1748

Merged
merged 14 commits into from
Nov 26, 2021
6 changes: 4 additions & 2 deletions .github/workflows/basic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -178,5 +178,7 @@ jobs:
run: mpirun -n 4 -oversubscribe python3 -m unittest discover -v -s python
- name: Run Python examples
run: scripts/run_python_examples.sh
- name: Build a catalogue
run: build-catalogue -v default mechanisms/default
- name: Build and test a catalogue
run: |
build-catalogue -v default mechanisms/default
./scripts/test-catalogue.py ./default-catalogue.so
8 changes: 1 addition & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,7 @@ install(TARGETS arbor-config-defs EXPORT arbor-targets)
# Interface library `arbor-private-deps` collects dependencies, options etc.
# for the arbor library.
add_library(arbor-private-deps INTERFACE)
target_link_libraries(arbor-private-deps INTERFACE arbor-config-defs ext-random123)
if (UNIX)
target_compile_definitions(arbor-config-defs INTERFACE ARB_HAVE_DL)
target_link_libraries(arbor-private-deps INTERFACE ${CMAKE_DL_LIBS})
else()
message(FATAL_ERROR "No support for dynamic loading on current platform.")
endif ()
target_link_libraries(arbor-private-deps INTERFACE arbor-config-defs ext-random123 ${CMAKE_DL_LIBS})
install(TARGETS arbor-private-deps EXPORT arbor-targets)

# Interface library `arborenv-private-deps` collects dependencies, options etc.
Expand Down
1 change: 1 addition & 0 deletions arbor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ set(arbor_sources
threading/threading.cpp
thread_private_spike_store.cpp
tree.cpp
util/dylib.cpp
util/hostname.cpp
util/unwind.cpp
version.cpp
Expand Down
18 changes: 9 additions & 9 deletions arbor/mechcat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
#include <arbor/mechanism.hpp>
#include <arbor/util/expected.hpp>

#include "util/rangeutil.hpp"
#include "util/dylib.hpp"
#include "util/maputil.hpp"
#include "util/rangeutil.hpp"
#include "util/span.hpp"
#include "util/dl.hpp"
#include "util/strprintf.hpp"

/* Notes on implementation:
*
Expand Down Expand Up @@ -587,18 +588,17 @@ const mechanism_catalogue& load_catalogue(const std::string& fn) {
typedef const void* global_catalogue_t();
global_catalogue_t* get_catalogue = nullptr;
try {
auto plugin = dl_open(fn);
get_catalogue = dl_get_symbol<global_catalogue_t*>(plugin, "get_catalogue");
} catch(dl_error& e) {
get_catalogue = util::dl_get_symbol<global_catalogue_t*>(fn, "get_catalogue");
} catch(util::dl_error& e) {
throw bad_catalogue_error{e.what(), {e}};
}
if (!get_catalogue) {
throw bad_catalogue_error{util::pprintf("Unusable symbol 'get_catalogue' in shared object '{}'", fn)};
}
/* NOTE We do not free the DSO handle here and accept retaining the handles
until termination since the mechanisms provided by the catalogue may have
a different lifetime than the actual catalogue itfself. This is not a
leak proper as `dlopen` caches handles for us.
/* The DSO handle is not freed here: handles will be retained until
* termination since the mechanisms provided by the catalogue may have a
* different lifetime than the actual catalogue itfself. This is not a leak,
* as `dlopen` caches handles for us.
*/
return *((const mechanism_catalogue*)get_catalogue());
}
Expand Down
5 changes: 0 additions & 5 deletions arbor/util/dl.hpp

This file was deleted.

52 changes: 0 additions & 52 deletions arbor/util/dl_platform_posix.hpp

This file was deleted.

50 changes: 50 additions & 0 deletions arbor/util/dylib.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <fstream>
#include <string>

#include <dlfcn.h>

#include <arbor/arbexcept.hpp>

#include "util/dylib.hpp"
#include "util/strprintf.hpp"

namespace arb {
namespace util {

void* dl_open(const std::string& fn) {
try {
std::ifstream fd{fn.c_str()};
if(!fd.good()) throw file_not_found_error{fn};
} catch(...) {
throw file_not_found_error{fn};
}
// Call once to clear errors not caused by us
dlerror();
auto result = dlopen(fn.c_str(), RTLD_LAZY);
// dlopen fails by returning NULL
if (nullptr == result) {
auto error = dlerror();
throw dl_error{util::pprintf("[POSIX] dl_open failed with: {}", error)};
}
return result;
}

namespace impl{
void* dl_get_symbol(const std::string& fn, const std::string& symbol) {
// Call once to clear errors not caused by us
dlerror();

auto handle = dl_open(fn);

// Get symbol from shared object, may return NULL if that is what symbol refers to
auto result = dlsym(handle, symbol.c_str());
// dlsym mayb return NULL even if succeeding
if (auto error = dlerror()) {
throw dl_error{util::pprintf("[POSIX] dl_get_symbol failed with: {}", error)};
}
return result;
}
} // namespace impl

} // namespace util
} // namespace arb
26 changes: 26 additions & 0 deletions arbor/util/dylib.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <string>

#include <arbor/arbexcept.hpp>

namespace arb {
namespace util {

namespace impl{
void* dl_get_symbol(const std::string& filename, const std::string& symbol);
} // namespace impl

struct dl_error: arbor_exception {
dl_error(const std::string& msg): arbor_exception{msg} {}
};

// Find and return a symbol from a dynamic library with filename.
// Throws dl_error on error.
template<typename T>
T dl_get_symbol(const std::string& filename, const std::string& symbol) {
return reinterpret_cast<T>(impl::dl_get_symbol(filename, symbol));
}

} // namespace util
} // namespace arbo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arbo?

21 changes: 21 additions & 0 deletions scripts/test-catalogue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env python3

import argparse
import os
import sys

import arbor

P = argparse.ArgumentParser(description='Verify that a mechanism catalogue can be loaded through Python interface.')
P.add_argument('catname', metavar='FILE', help='path of the catalogue to test.')

args = P.parse_args()
catname = args.catname

print(catname)

if not os.path.isfile(catname):
print('ERROR: unable to open catalogue file')
sys.exit(1)

print([n for n in arbor.load_catalogue(catname).keys()])