diff --git a/brian2/codegen/codeobject.py b/brian2/codegen/codeobject.py index bb6c71029..038e5cea6 100644 --- a/brian2/codegen/codeobject.py +++ b/brian2/codegen/codeobject.py @@ -5,6 +5,7 @@ import collections import copy import platform +from abc import ABC, abstractmethod from brian2.core.base import weakproxy_with_fallback from brian2.core.functions import DEFAULT_FUNCTIONS, Function @@ -42,7 +43,7 @@ def constant_or_scalar(varname, variable): return f"{varname}" -class CodeObject(Nameable): +class CodeObject(Nameable, ABC): """ Executable code object. @@ -105,9 +106,7 @@ def is_available(cls): Whether this target for code generation is available. Should use a minimal example to check whether code generation works in general. """ - raise NotImplementedError( - f"CodeObject class {cls.__name__} is missing an 'is_available' method." - ) + return True def update_namespace(self): """ @@ -117,8 +116,8 @@ def update_namespace(self): """ pass - def compile_block(self, block): - raise NotImplementedError("Implement compile_block method") + @abstractmethod + def compile_block(self, block): ... def compile(self): for block in ["before_run", "run", "after_run"]: @@ -130,8 +129,8 @@ def __call__(self, **kwds): return self.run() - def run_block(self, block): - raise NotImplementedError("Implement run_block method") + @abstractmethod + def run_block(self, block): ... def before_run(self): """ diff --git a/brian2/codegen/generators/GSL_generator.py b/brian2/codegen/generators/GSL_generator.py index f5b281e50..f14d16bfe 100644 --- a/brian2/codegen/generators/GSL_generator.py +++ b/brian2/codegen/generators/GSL_generator.py @@ -1110,7 +1110,7 @@ def __getattr__(self, item): syntax = { "end_statement": ";", "access_pointer": "->", - "start_declare": 'extern "C" ', + "start_declare": "", "open_function": "\n{", "open_struct": "\n{", "end_function": "\n}", @@ -1159,3 +1159,14 @@ def unpack_namespace_single(self, var_obj, in_vector, in_scalar): return f"_GSL_dataholder.{var_obj.name} = {var_obj.name};" else: return "" + + def make_function_code(self, lines): + # To pass constants that might be used in the function, we need to + # add a %CONSTANTS% placeholder that will be replaced by the standalone + # device + return """ + // CONSTANTS + %CONSTANTS% + """ + super().make_function_code( + lines + ) diff --git a/brian2/codegen/runtime/numpy_rt/numpy_rt.py b/brian2/codegen/runtime/numpy_rt/numpy_rt.py index d56e8b855..1553f7b55 100644 --- a/brian2/codegen/runtime/numpy_rt/numpy_rt.py +++ b/brian2/codegen/runtime/numpy_rt/numpy_rt.py @@ -200,11 +200,6 @@ def __init__( ) self.variables_to_namespace() - @classmethod - def is_available(cls): - # no test necessary for numpy - return True - def variables_to_namespace(self): # Variables can refer to values that are either constant (e.g. dt) # or change every timestep (e.g. t). We add the values of the diff --git a/brian2/codegen/templates.py b/brian2/codegen/templates.py index 31a6693ba..22f93c73f 100644 --- a/brian2/codegen/templates.py +++ b/brian2/codegen/templates.py @@ -144,7 +144,10 @@ def __init__( self.templates = LazyTemplateLoader(self.env, extension) def __getattr__(self, item): - return self.templates.get_template(item) + try: + return self.templates.get_template(item) + except KeyError as ex: + raise AttributeError from ex # raise the correct error type for __getattr__ def derive( self, package_name, extension=None, env_globals=None, templates_dir="templates" diff --git a/brian2/devices/cpp_standalone/GSLcodeobject.py b/brian2/devices/cpp_standalone/GSLcodeobject.py index 6ef49966f..867698668 100644 --- a/brian2/devices/cpp_standalone/GSLcodeobject.py +++ b/brian2/devices/cpp_standalone/GSLcodeobject.py @@ -3,13 +3,12 @@ GNU Scientific Library """ -from brian2.codegen.codeobject import CodeObject from brian2.codegen.generators.cpp_generator import CPPCodeGenerator from brian2.codegen.generators.GSL_generator import GSLCPPCodeGenerator from brian2.devices.cpp_standalone import CPPStandaloneCodeObject -class GSLCPPStandaloneCodeObject(CodeObject): +class GSLCPPStandaloneCodeObject(CPPStandaloneCodeObject): templater = CPPStandaloneCodeObject.templater.derive( "brian2.devices.cpp_standalone", templates_dir="templates_GSL" ) diff --git a/brian2/stateupdaters/GSL.py b/brian2/stateupdaters/GSL.py index ca3032fea..671844a8d 100644 --- a/brian2/stateupdaters/GSL.py +++ b/brian2/stateupdaters/GSL.py @@ -3,6 +3,7 @@ provided in the GNU Scientific Library (GSL) """ +import os import sys from brian2.utils.logger import get_logger @@ -105,6 +106,9 @@ def get_codeobj_class(self): device.define_macros += [("WIN32", "1"), ("GSL_DLL", "1")] if prefs.GSL.directory is not None: device.include_dirs += [prefs.GSL.directory] + device.library_dirs += [ + os.path.abspath(os.path.join(prefs.GSL.directory, "..", "lib")) + ] return GSLCPPStandaloneCodeObject elif isinstance(device, RuntimeDevice):