diff --git a/CMakeLists.txt b/CMakeLists.txt
index 106b5d6bdb94450fb6f267c55be465e475779533..521c5a80fbc16eefaa04ef234c9b54fb2b64dc5f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -135,13 +135,13 @@ set(USE_OPTIMIZED_KERNELS OFF CACHE BOOL "generate optimized code that vectorize
 # Only build modcc if it has not already been installed.
 # This is useful if cross compiling for KNL, when it is not desirable to compile
 # modcc with the same flags that are used for the KNL target.
-set(use_external_modcc OFF BOOL)
+set(use_external_modcc OFF)
 find_program(MODCC_BIN modcc)
 if(MODCC_BIN STREQUAL "MODCC_BIN-NOTFOUND")
     set(modcc "${CMAKE_BINARY_DIR}/modcc/modcc")
 else()
+    set(use_external_modcc ON)
     set(modcc "${MODCC_BIN}")
-    set(use_external_modcc ON BOOL)
 endif()
 
 # Validation data generation
@@ -187,7 +187,7 @@ if(BUILD_VALIDATION_DATA)
 endif()
 
 # only compile modcc if it is not provided externally
-if(use_external_modcc)
+if(NOT use_external_modcc)
     add_subdirectory(modcc)
 endif()
 
diff --git a/mechanisms/BuildModules.cmake b/mechanisms/BuildModules.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..88674f9a6c2b8a941b0c158753aa83ec14e48a71
--- /dev/null
+++ b/mechanisms/BuildModules.cmake
@@ -0,0 +1,40 @@
+include(CMakeParseArguments)
+
+# Uses CMake variables modcc and use_external_modcc as set in top level CMakeLists.txt
+
+function(build_modules)
+    cmake_parse_arguments(build_modules "" "TARGET;SOURCE_DIR;DEST_DIR;MECH_SUFFIX" "MODCC_FLAGS" ${ARGN})
+
+    foreach(mech ${build_modules_UNPARSED_ARGUMENTS})
+        set(mod "${build_modules_SOURCE_DIR}/${mech}.mod")
+        set(hpp "${build_modules_DEST_DIR}/${mech}.hpp")
+
+        set(depends "${mod}")
+        if(NOT use_external_modcc)
+            list(APPEND depends modcc)
+        endif()
+
+        set(flags ${build_modules_MODCC_FLAGS} -o "${hpp}")
+        if(build_modules_MECH_SUFFIX)
+            list(APPEND flags -m "${mech}${build_modules_MECH_SUFFIX}")
+        endif()
+
+        add_custom_command(
+            OUTPUT "${hpp}"
+            DEPENDS ${depends}
+            WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+            COMMAND ${modcc} ${flags} ${mod}
+        )
+        set_source_files_properties("${hpp}" PROPERTIES GENERATED TRUE)
+        list(APPEND all_mod_hpps "${hpp}")
+    endforeach()
+
+    # Fake target to always trigger .mod -> .hpp dependencies because wtf CMake
+    if (build_modules_TARGET)
+        set(depends ${all_mod_hpps})
+        if(NOT use_external_modcc)
+            list(APPEND depends modcc)
+        endif()
+        add_custom_target(${build_modules_TARGET} DEPENDS ${depends})
+    endif()
+endfunction()
diff --git a/mechanisms/CMakeLists.txt b/mechanisms/CMakeLists.txt
index d7ad64000dfbc0e7946e1f87529a58b4d4106368..71c4643f049f1f94e4d53305010c72f826345109 100644
--- a/mechanisms/CMakeLists.txt
+++ b/mechanisms/CMakeLists.txt
@@ -1,77 +1,34 @@
+include(BuildModules.cmake)
+
 # the list of built-in mechanisms to be provided by default
 set(mechanisms pas hh expsyn exp2syn)
 
-# set the flags for the modcc compiler that converts NMODL
-# files to C++/CUDA source.
-set(modcc_flags "-t cpu")
-
+set(modcc_opt)
 if(USE_OPTIMIZED_KERNELS) # generate optimized kernels
-    set(modcc_flags ${modcc_flags} -O)
-endif()
-
-# make path for the kernels that will be generated by modcc
-file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/multicore)
-if(WITH_CUDA)
-    file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/gpu)
+    set(modcc_opt "-O")
 endif()
 
-# generate source for each mechanism
-foreach(mech ${mechanisms})
-    set(mod "${CMAKE_CURRENT_SOURCE_DIR}/mod/${mech}.mod")
-    set(hpp "${CMAKE_CURRENT_SOURCE_DIR}/multicore/${mech}.hpp")
-    if(use_external_modcc)
-        add_custom_command(
-           OUTPUT "${hpp}"
-           WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
-           COMMAND ${modcc} ${modcc_flags} ${mod} -o ${hpp}
-       )
-    else()
-        add_custom_command(
-            OUTPUT "${hpp}"
-            DEPENDS modcc "${mod}"
-            WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
-            COMMAND ${modcc} ${modcc_flags} ${mod} -o ${hpp}
-        )
-    endif()
-    set_source_files_properties("${hpp}" PROPERTIES GENERATED TRUE)
-    list(APPEND all_mod_hpps "${hpp}")
-endforeach()
+set(mod_srcdir "${CMAKE_CURRENT_SOURCE_DIR}/mod")
 
-# Fake target to always trigger .mod -> .hpp dependencies because wtf CMake
-add_custom_target(build_all_mods DEPENDS ${all_mod_hpps} modcc)
+set(mech_dir "${CMAKE_CURRENT_SOURCE_DIR}/multicore")
+file(MAKE_DIRECTORY "${mech_dir}")
+build_modules(
+    ${mechanisms}
+    SOURCE_DIR "${mod_srcdir}"
+    DEST_DIR "${mech_dir}"
+    MODCC_FLAGS -t cpu ${modcc_opt}
+    TARGET build_all_mods
+)
 
-# oh sweet jesus, CMake is a dog's breakfast.
-# that said, let'g go through the same dance to generate CUDA kernels if
-# we are targetting the GPU.
 if(WITH_CUDA)
-    set(modcc_flags "-t gpu")
-
-    if(USE_OPTIMIZED_KERNELS)
-        set(modcc_flags ${modcc_flags} -O)
-    endif()
-
-    # generate source for each mechanism
-    foreach(mech ${mechanisms})
-        set(mod "${CMAKE_CURRENT_SOURCE_DIR}/mod/${mech}.mod")
-        set(hpp "${CMAKE_CURRENT_SOURCE_DIR}/gpu/${mech}.hpp")
-        if(use_external_modcc)
-            add_custom_command(
-               OUTPUT "${hpp}"
-               WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
-               COMMAND ${modcc} ${modcc_flags} ${mod} -o ${hpp}
-           )
-        else()
-            add_custom_command(
-                OUTPUT "${hpp}"
-                DEPENDS modparser "${mod}"
-                WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
-                COMMAND ${modcc} ${modcc_flags} ${mod} -o ${hpp}
-            )
-        endif()
-        set_source_files_properties("${hpp}" PROPERTIES GENERATED TRUE)
-        list(APPEND all_gpu_mod_hpps "${hpp}")
-    endforeach()
-
-    # Fake target to always trigger .mod -> .hpp dependencies because wtf CMake
-    add_custom_target(build_all_gpu_mods DEPENDS ${all_gpu_mod_hpps} modcc)
+    set(mech_dir "${CMAKE_CURRENT_SOURCE_DIR}/gpu")
+    file(MAKE_DIRECTORY "${mech_dir}")
+    build_modules(
+        ${mechanisms}
+        SOURCE_DIR "${mod_srcdir}"
+        DEST_DIR "${mech_dir}"
+        MODCC_FLAGS -t gpu ${modcc_opt}
+        TARGET build_all_gpu_mods
+    )
 endif()
+
diff --git a/modcc/cprinter.cpp b/modcc/cprinter.cpp
index beb97a673d28f2b6c24bbb250dd579f945dfd9cb..c588c5ec2af70a59a34c79384f2b9cf23895a980 100644
--- a/modcc/cprinter.cpp
+++ b/modcc/cprinter.cpp
@@ -2,6 +2,7 @@
 
 #include "cprinter.hpp"
 #include "lexer.hpp"
+#include "options.hpp"
 
 /******************************************************************************
                               CPrinter driver
@@ -26,6 +27,11 @@ CPrinter::CPrinter(Module &m, bool o)
         }
     }
 
+    std::string module_name = Options::instance().modulename;
+    if (module_name == "") {
+        module_name = m.name();
+    }
+
     //////////////////////////////////////////////
     //////////////////////////////////////////////
     text_.add_line("#pragma once");
@@ -40,9 +46,9 @@ CPrinter::CPrinter(Module &m, bool o)
 
     //////////////////////////////////////////////
     //////////////////////////////////////////////
-    std::string class_name = "mechanism_" + m.name();
+    std::string class_name = "mechanism_" + module_name;
 
-    text_.add_line("namespace nest{ namespace mc{ namespace mechanisms{ namespace " + m.name() + "{");
+    text_.add_line("namespace nest{ namespace mc{ namespace mechanisms{ namespace " + module_name + "{");
     text_.add_line();
     text_.add_line("template<class Backend>");
     text_.add_line("class " + class_name + " : public mechanism<Backend> {");
@@ -182,7 +188,7 @@ CPrinter::CPrinter(Module &m, bool o)
 
     text_.add_line("std::string name() const override {");
     text_.increase_indentation();
-    text_.add_line("return \"" + m.name() + "\";");
+    text_.add_line("return \"" + module_name + "\";");
     text_.decrease_indentation();
     text_.add_line("}");
     text_.add_line();
@@ -861,4 +867,3 @@ void CPrinter::visit(BinaryExpression *e) {
     // reset parent precedence
     parent_op_ = pop;
 }
-
diff --git a/modcc/cudaprinter.cpp b/modcc/cudaprinter.cpp
index c6c33ead52ef2131d3efc6582a603026ee5f3868..23246ea69295163bc883494f9e11d49787471a09 100644
--- a/modcc/cudaprinter.cpp
+++ b/modcc/cudaprinter.cpp
@@ -3,6 +3,7 @@
 #include "cprinter.hpp" // needed for printing net_receive method
 #include "cudaprinter.hpp"
 #include "lexer.hpp"
+#include "options.hpp"
 
 /******************************************************************************
 ******************************************************************************/
@@ -26,6 +27,11 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o)
         }
     }
 
+    std::string module_name = Options::instance().modulename;
+    if (module_name == "") {
+        module_name = m.name();
+    }
+
     //////////////////////////////////////////////
     // header files
     //////////////////////////////////////////////
@@ -39,7 +45,7 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o)
     text_.add_line("#include <util/pprintf.hpp>");
     text_.add_line();
 
-    text_.add_line("namespace nest{ namespace mc{ namespace mechanisms{ namespace gpu{ namespace " + m.name() + "{");
+    text_.add_line("namespace nest{ namespace mc{ namespace mechanisms{ namespace gpu{ namespace " + module_name + "{");
     text_.add_line();
     increase_indentation();
 
@@ -48,7 +54,7 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o)
     ////////////////////////////////////////////////////////////
     std::vector<std::string> param_pack;
     text_.add_line("template <typename T, typename I>");
-    text_.add_gutter() << "struct " << m.name() << "_ParamPack {";
+    text_.add_gutter() << "struct " << module_name << "_ParamPack {";
     text_.end_line();
     text_.increase_indentation();
     text_.add_line("// array parameters");
@@ -141,7 +147,7 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o)
 
     //////////////////////////////////////////////
     //////////////////////////////////////////////
-    std::string class_name = "mechanism_" + m.name();
+    std::string class_name = "mechanism_" + module_name;
 
     text_.add_line("template<typename Backend>");
     text_.add_line("class " + class_name + " : public mechanism<Backend> {");
@@ -159,7 +165,7 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o)
     text_.add_line("using typename base::const_view;");
     text_.add_line("using typename base::indexed_view_type;");
     text_.add_line("using typename base::ion_type;");
-    text_.add_line("using param_pack_type = " + m.name() + "_ParamPack<value_type, size_type>;");
+    text_.add_line("using param_pack_type = " + module_name + "_ParamPack<value_type, size_type>;");
 
     //////////////////////////////////////////////
     //////////////////////////////////////////////
@@ -286,7 +292,7 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o)
     // name member function
     text_.add_line("std::string name() const override {");
     text_.increase_indentation();
-    text_.add_line("return \"" + m.name() + "\";");
+    text_.add_line("return \"" + module_name + "\";");
     text_.decrease_indentation();
     text_.add_line("}");
     text_.add_line();
@@ -420,7 +426,7 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o)
     //////////////////////////////////////////////
     //////////////////////////////////////////////
     for(auto const &var : m.symbols()) {
-        if( var.second->kind()==symbolKind::procedure && 
+        if( var.second->kind()==symbolKind::procedure &&
             var.second->is_procedure()->kind()==procedureKind::api)
         {
             auto proc = var.second->is_api_method();
@@ -884,4 +890,3 @@ void CUDAPrinter::visit(BinaryExpression *e) {
     // reset parent precedence
     parent_op_ = pop;
 }
-
diff --git a/modcc/modcc.cpp b/modcc/modcc.cpp
index eb2b29e9351e927b7c32d0a24ffd0ba464d1a547..5a642cec5e3565f30fd52a75ba3cd44f8bcbc8cb 100644
--- a/modcc/modcc.cpp
+++ b/modcc/modcc.cpp
@@ -11,37 +11,12 @@
 #include "parser.hpp"
 #include "perfvisitor.hpp"
 #include "modccutil.hpp"
+#include "options.hpp"
 
 //#define VERBOSE
 
-enum class targetKind {cpu, gpu};
-
-struct Options {
-    std::string filename;
-    std::string outputname;
-    bool has_output = false;
-    bool verbose = true;
-    bool optimize = false;
-    bool analysis = false;
-    targetKind target = targetKind::cpu;
-
-    void print() {
-        std::cout << cyan("." + std::string(60, '-') + ".") << std::endl;
-        std::cout << cyan("| file     ") << filename << std::string(61-11-filename.size(),' ') << cyan("|") << std::endl;
-        std::string outname = (outputname.size() ? outputname : "stdout");
-        std::cout << cyan("| output   ") << outname << std::string(61-11-outname.size(),' ') << cyan("|") << std::endl;
-        std::cout << cyan("| verbose  ") << (verbose  ? "yes" : "no ") << std::string(61-11-3,' ') << cyan("|") << std::endl;
-        std::cout << cyan("| optimize ") << (optimize ? "yes" : "no ") << std::string(61-11-3,' ') << cyan("|") << std::endl;
-        std::cout << cyan("| target   ") << (target==targetKind::cpu? "cpu" : "gpu") << std::string(61-11-3,' ') << cyan("|") << std::endl;
-        std::cout << cyan("| analysis ") << (analysis ? "yes" : "no ") << std::string(61-11-3,' ') << cyan("|") << std::endl;
-        std::cout << cyan("." + std::string(60, '-') + ".") << std::endl;
-    }
-};
-
 int main(int argc, char **argv) {
 
-    Options options;
-
     // parse command line arguments
     try {
         TCLAP::CmdLine cmd("welcome to mod2c", ' ', "0.1");
@@ -51,7 +26,7 @@ int main(int argc, char **argv) {
             fin_arg("input_file", "the name of the .mod file to compile", true, "", "filename");
         // output filename
         TCLAP::ValueArg<std::string>
-            fout_arg("o","output","name of output file", false,"","filname");
+            fout_arg("o","output","name of output file", false,"","filename");
         // output filename
         TCLAP::ValueArg<std::string>
             target_arg("t","target","backend target={cpu,gpu}", true,"cpu","cpu/gpu");
@@ -61,41 +36,45 @@ int main(int argc, char **argv) {
         TCLAP::SwitchArg analysis_arg("A","analyse","toggle analysis mode", cmd, false);
         // optimization mode
         TCLAP::SwitchArg opt_arg("O","optimize","turn optimizations on", cmd, false);
+        // Set module name explicitly
+        TCLAP::ValueArg<std::string>
+            module_arg("m", "module", "module name to use", false, "", "module");
 
         cmd.add(fin_arg);
         cmd.add(fout_arg);
         cmd.add(target_arg);
+        cmd.add(module_arg);
 
         cmd.parse(argc, argv);
 
-        options.outputname = fout_arg.getValue();
-        options.has_output = options.outputname.size()>0;
-        options.filename = fin_arg.getValue();
-        options.verbose = verbose_arg.getValue();
-        options.optimize = opt_arg.getValue();
-        options.analysis = analysis_arg.getValue();
+        Options::instance().outputname = fout_arg.getValue();
+        Options::instance().has_output = Options::instance().outputname.size()>0;
+        Options::instance().filename = fin_arg.getValue();
+        Options::instance().modulename = module_arg.getValue();
+        Options::instance().verbose = verbose_arg.getValue();
+        Options::instance().optimize = opt_arg.getValue();
+        Options::instance().analysis = analysis_arg.getValue();
         auto targstr = target_arg.getValue();
         if(targstr == "cpu") {
-            options.target = targetKind::cpu;
+            Options::instance().target = targetKind::cpu;
         }
         else if(targstr == "gpu") {
-            options.target = targetKind::gpu;
+            Options::instance().target = targetKind::gpu;
         }
         else {
-            std::cerr << red("error") << " target must be one in {cpu, gpu}" << std::endl;
+            std::cerr << red("error") << " target must be one in {cpu, gpu}\n";
             return 1;
         }
     }
     // catch any exceptions in command line handling
     catch(TCLAP::ArgException &e) {
-        std::cerr << "error: " << e.error()
-                  << " for arg " << e.argId()
-                  << std::endl;
+        std::cerr << "error: "   << e.error()
+                  << " for arg " << e.argId() << "\n";
     }
 
     try {
         // load the module from file passed as first argument
-        Module m(options.filename.c_str());
+        Module m(Options::instance().filename.c_str());
 
         // check that the module is not empty
         if(m.buffer().size()==0) {
@@ -104,14 +83,14 @@ int main(int argc, char **argv) {
             return 1;
         }
 
-        if(options.verbose) {
-            options.print();
+        if(Options::instance().verbose) {
+            Options::instance().print();
         }
 
         ////////////////////////////////////////////////////////////
         // parsing
         ////////////////////////////////////////////////////////////
-        if(options.verbose) std::cout << green("[") + "parsing" + green("]") << std::endl;
+        if(Options::instance().verbose) std::cout << green("[") + "parsing" + green("]") << std::endl;
 
         // initialize the parser
         Parser p(m, false);
@@ -123,7 +102,7 @@ int main(int argc, char **argv) {
         ////////////////////////////////////////////////////////////
         // semantic analysis
         ////////////////////////////////////////////////////////////
-        if(options.verbose)
+        if(Options::instance().verbose)
             std::cout << green("[") + "semantic analysis" + green("]") << "\n";
 
         m.semantic();
@@ -139,8 +118,8 @@ int main(int argc, char **argv) {
         ////////////////////////////////////////////////////////////
         // optimize
         ////////////////////////////////////////////////////////////
-        if(options.optimize) {
-            if(options.verbose) std::cout << green("[") + "optimize" + green("]") << std::endl;
+        if(Options::instance().optimize) {
+            if(Options::instance().verbose) std::cout << green("[") + "optimize" + green("]") << std::endl;
             m.optimize();
             if(m.status() == lexerStatus::error) {
                 return 1;
@@ -150,47 +129,49 @@ int main(int argc, char **argv) {
         ////////////////////////////////////////////////////////////
         // generate output
         ////////////////////////////////////////////////////////////
-        if(options.verbose) {
+        if(Options::instance().verbose) {
             std::cout << green("[") + "code generation"
                       << green("]") << std::endl;
         }
 
         std::string text;
-        switch(options.target) {
+        switch(Options::instance().target) {
             case targetKind::cpu  :
-                text = CPrinter(m, options.optimize).text();
+                text = CPrinter(m, Options::instance().optimize).text();
                 break;
             case targetKind::gpu  :
-                text = CUDAPrinter(m, options.optimize).text();
+                text = CUDAPrinter(m, Options::instance().optimize).text();
                 break;
             default :
                 std::cerr << red("error") << ": unknown printer" << std::endl;
                 exit(1);
         }
 
-        if(options.has_output) {
-            std::ofstream fout(options.outputname);
+        if(Options::instance().has_output) {
+            std::ofstream fout(Options::instance().outputname);
             fout << text;
             fout.close();
         }
         else {
-            std::cout << cyan("--------------------------------------") << std::endl;
+            std::cout << cyan("--------------------------------------\n");
             std::cout << text;
-            std::cout << cyan("--------------------------------------") << std::endl;
+            std::cout << cyan("--------------------------------------\n");
         }
 
-        std::cout << yellow("successfully compiled ") << white(options.filename) << " -> " << white(options.outputname) << std::endl;
+        std::cout << yellow("successfully compiled ")
+                  << white(Options::instance().filename) << " -> "
+                  << white(Options::instance().outputname) << "\n";
 
         ////////////////////////////////////////////////////////////
         // print module information
         ////////////////////////////////////////////////////////////
-        if(options.analysis) {
+        if(Options::instance().analysis) {
             std::cout << green("performance analysis") << std::endl;
             for(auto &symbol : m.symbols()) {
                 if(auto method = symbol.second->is_api_method()) {
-                    std::cout << white("-------------------------") << std::endl;
-                    std::cout << yellow("method " + method->name()) << std::endl;
-                    std::cout << white("-------------------------") << std::endl;
+                    std::cout << white("-------------------------\n");
+                    std::cout << yellow("method " + method->name()) << "\n";
+                    std::cout << white("-------------------------\n");
 
                     auto flops = make_unique<FlopVisitor>();
                     method->accept(flops.get());
@@ -209,24 +190,21 @@ int main(int argc, char **argv) {
     catch(compiler_exception e) {
         std::cerr << red("internal compiler error: ")
                   << white("this means a bug in the compiler,"
-                           " please report to modcc developers")
-                  << std::endl
-                  << e.what() << " @ " << e.location() << std::endl;
+                           " please report to modcc developers\n")
+                  << e.what() << " @ " << e.location() << "\n";
         exit(1);
     }
     catch(std::exception e) {
         std::cerr << red("internal compiler error: ")
                   << white("this means a bug in the compiler,"
-                           " please report to modcc developers")
-                  << std::endl
-                  << e.what() << std::endl;
+                           " please report to modcc developers\n")
+                  << e.what() << "\n";
         exit(1);
     }
     catch(...) {
         std::cerr << red("internal compiler error: ")
                   << white("this means a bug in the compiler,"
-                           " please report to modcc developers")
-                  << std::endl;
+                           " please report to modcc developers\n");
         exit(1);
     }
 
diff --git a/modcc/options.hpp b/modcc/options.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d994740e79e73c06030b774b710b56dc805da7a4
--- /dev/null
+++ b/modcc/options.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <iostream>
+
+enum class targetKind { cpu, gpu };
+
+struct Options {
+    std::string filename;
+    std::string outputname;
+    std::string modulename;
+    bool has_output = false;
+    bool verbose = true;
+    bool optimize = false;
+    bool analysis = false;
+    targetKind target = targetKind::cpu;
+
+    void print() {
+        std::cout << cyan("." + std::string(60, '-') + ".") << "\n";
+        std::cout << cyan("| file     ") << filename
+                  << std::string(61-11-filename.size(),' ')
+                  << cyan("|") << "\n";
+
+        std::string outname = (outputname.size() ? outputname : "stdout");
+        std::cout << cyan("| output   ") << outname
+                  << std::string(61-11-outname.size(),' ')
+                  << cyan("|") << "\n";
+        std::cout << cyan("| verbose  ") << (verbose  ? "yes" : "no ")
+                  << std::string(61-11-3,' ') << cyan("|") << "\n";
+        std::cout << cyan("| optimize ") << (optimize ? "yes" : "no ")
+                  << std::string(61-11-3,' ') << cyan("|") << "\n";
+        std::cout << cyan("| target   ")
+                  << (target==targetKind::cpu? "cpu" : "gpu")
+                  << std::string(61-11-3,' ') << cyan("|") << "\n";
+        std::cout << cyan("| analysis ") << (analysis ? "yes" : "no ")
+                  << std::string(61-11-3,' ') << cyan("|") << "\n";
+        std::cout << cyan("." + std::string(60, '-') + ".") << std::endl;
+    }
+
+    Options(const Options& other) = delete;
+    void operator=(const Options& other) = delete;
+
+    static Options& instance() {
+        static Options instance;
+        return instance;
+    }
+
+private:
+    Options() {}
+};
diff --git a/src/util/cycle.hpp b/src/util/cycle.hpp
index a4405bdbce6b0d4c391b3e1275c86641faaf3cd5..66611f1c3601aea36f921c21c4f57ce85b1d3807 100644
--- a/src/util/cycle.hpp
+++ b/src/util/cycle.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <initializer_list>
 #include <utility>
 #include <util/iterutil.hpp>
 #include <util/range.hpp>
@@ -205,6 +206,15 @@ cyclic_view(const Seq& s) {
     return { make_cyclic_iterator(cbegin(s), cend(s)), cend(s) };
 }
 
+// Handle initializer lists
+template <typename T>
+range<cyclic_iterator<typename std::initializer_list<T>::const_iterator,
+                      typename std::initializer_list<T>::const_iterator> >
+cyclic_view(const std::initializer_list<T> &list) {
+    return { make_cyclic_iterator(cbegin(list), cend(list)),
+             make_cyclic_iterator(cend(list), cend(list)) };
+}
+
 } // namespace util
 } // namespace mc
 } // namespace nest
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index 45de971662d68f0972cda67419655ea5c574eb4b..b211b296f2de918be2c6b40cd06af53e86e5a57e 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -1,3 +1,21 @@
+include(${CMAKE_SOURCE_DIR}/mechanisms/BuildModules.cmake)
+
+# Build prototype mechanisms for testing in test_mechanisms.
+set(proto_mechanisms pas hh expsyn exp2syn)
+set(mech_proto_dir "${CMAKE_CURRENT_BINARY_DIR}/mech_proto")
+file(MAKE_DIRECTORY "${mech_proto_dir}")
+
+build_modules(
+    ${proto_mechanisms}
+    SOURCE_DIR "${CMAKE_SOURCE_DIR}/mechanisms/mod"
+    DEST_DIR "${mech_proto_dir}"
+    MECH_SUFFIX _proto
+    MODCC_FLAGS -t cpu
+    TARGET build_test_mods
+)
+
+# Unit test sources
+
 set(TEST_CUDA_SOURCES
     test_cell_group.cu
     test_matrix.cu
@@ -54,6 +72,8 @@ add_definitions("-DDATADIR=\"${CMAKE_SOURCE_DIR}/data\"")
 set(TARGETS test.exe)
 
 add_executable(test.exe ${TEST_SOURCES} ${HEADERS})
+add_dependencies(test.exe build_test_mods)
+target_include_directories(test.exe PRIVATE "${mech_proto_dir}/..")
 
 if(WITH_CUDA)
     set(TARGETS ${TARGETS} test_cuda.exe)
@@ -75,4 +95,3 @@ foreach(target ${TARGETS})
        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests"
     )
 endforeach()
-
diff --git a/tests/unit/test_cycle.cpp b/tests/unit/test_cycle.cpp
index d022a666b2f03308e6d951dd06aa153eef68a929..621f4515bb160b552470b646cdd2d646a8024916 100644
--- a/tests/unit/test_cycle.cpp
+++ b/tests/unit/test_cycle.cpp
@@ -147,6 +147,20 @@ TEST(cycle, cyclic_view) {
     }
 }
 
+TEST(cycle, cyclic_view_initlist) {
+    std::vector<int> values;
+
+    std::copy_n(util::cyclic_view({2., 3., 4.}).cbegin(), 10,
+                std::back_inserter(values));
+
+    EXPECT_EQ(10u, values.size());
+
+    auto i = 0;
+    for (auto const& v : values) {
+        EXPECT_EQ(2 + i++ % 3, v);
+    }
+}
+
 TEST(cycle_iterator, difference) {
     int values[] = { 4, 2, 3 };
 
diff --git a/tests/unit/test_mechanisms.cpp b/tests/unit/test_mechanisms.cpp
index fbc0989c66a25098ad816807cf3991e06707cf95..58ffd34efb2152a734124515cb2408d727fd5703 100644
--- a/tests/unit/test_mechanisms.cpp
+++ b/tests/unit/test_mechanisms.cpp
@@ -1,7 +1,24 @@
 #include "../gtest.h"
 
-#include <matrix.hpp>
+// Prototype mechanisms in tests
+#include "mech_proto/expsyn.hpp"
+#include "mech_proto/exp2syn.hpp"
+#include "mech_proto/hh.hpp"
+#include "mech_proto/pas.hpp"
+
+// modcc generated mechanisms
+#include "mechanisms/multicore/expsyn.hpp"
+#include "mechanisms/multicore/exp2syn.hpp"
+#include "mechanisms/multicore/hh.hpp"
+#include "mechanisms/multicore/pas.hpp"
+
+#include <initializer_list>
 #include <backends/fvm_multicore.hpp>
+#include <ion.hpp>
+#include <matrix.hpp>
+#include <memory/wrappers.hpp>
+#include <util/rangeutil.hpp>
+#include <util/cycle.hpp>
 
 TEST(mechanisms, helpers) {
     using namespace nest::mc;
@@ -32,3 +49,154 @@ TEST(mechanisms, helpers) {
         std::out_of_range
     );
 }
+
+// Setup and update mechanism
+template<typename T>
+void mech_update(T* mech, int num_iters) {
+
+    using namespace nest::mc;
+    std::map<mechanisms::ionKind, mechanisms::ion<typename T::backend>> ions;
+
+    mech->set_params(2., 0.1);
+    mech->nrn_init();
+    for (auto ion_kind : mechanisms::ion_kinds()) {
+        auto ion_indexes = util::make_copy<std::vector<typename T::size_type>>(
+            mech->node_index_
+        );
+
+        // Create and fill in the ion
+        mechanisms::ion<typename T::backend> ion = ion_indexes;
+
+        memory::fill(ion.current(), 5.);
+        memory::fill(ion.reversal_potential(), 100.);
+        memory::fill(ion.internal_concentration(), 10.);
+        memory::fill(ion.external_concentration(), 140.);
+        ions[ion_kind] = ion;
+
+        if (mech->uses_ion(ion_kind)) {
+            mech->set_ion(ion_kind, ions[ion_kind], ion_indexes);
+        }
+    }
+
+    for (auto i = 0; i < mech->node_index_.size(); ++i) {
+        mech->net_receive(i, 1.);
+    }
+
+    for (auto i = 0; i < num_iters; ++i) {
+        mech->nrn_current();
+        mech->nrn_state();
+    }
+}
+
+template<typename T, typename Seq>
+void array_init(T& array, const Seq& seq) {
+    auto seq_iter = seq.cbegin();
+    for (auto& e : array) {
+        e = *seq_iter++;
+    }
+}
+
+template<typename S, typename T, bool alias = false>
+struct mechanism_info {
+    using mechanism_type = S;
+    using proto_mechanism_type = T;
+    static constexpr bool index_aliasing = alias;
+};
+
+template<typename T>
+class mechanisms : public ::testing::Test { };
+
+TYPED_TEST_CASE_P(mechanisms);
+
+TYPED_TEST_P(mechanisms, update) {
+    using mechanism_type = typename TypeParam::mechanism_type;
+    using proto_mechanism_type = typename TypeParam::proto_mechanism_type;
+
+    // Type checking
+    EXPECT_TRUE((std::is_same<typename proto_mechanism_type::iarray,
+                              typename mechanism_type::iarray>::value));
+    EXPECT_TRUE((std::is_same<typename proto_mechanism_type::value_type,
+                              typename mechanism_type::value_type>::value));
+    EXPECT_TRUE((std::is_same<typename proto_mechanism_type::array,
+                              typename mechanism_type::array>::value));
+
+    auto num_syn = 32;
+
+    typename mechanism_type::iarray indexes(num_syn);
+    typename mechanism_type::array  voltage(num_syn, -65.0);
+    typename mechanism_type::array  current(num_syn,   1.0);
+    typename mechanism_type::array  weights(num_syn,   1.0);
+
+    array_init(voltage, nest::mc::util::cyclic_view({ -65.0, -61.0, -63.0 }));
+    array_init(current, nest::mc::util::cyclic_view({   1.0,   0.9,   1.1 }));
+    array_init(weights, nest::mc::util::cyclic_view({ 1.0 }));
+
+    // Initialise indexes
+    std::vector<int> index_freq;
+    if (TypeParam::index_aliasing) {
+        index_freq.assign({ 4, 2, 3 });
+    }
+    else {
+        index_freq.assign({ 1 });
+    }
+
+    auto freq_begin = nest::mc::util::cyclic_view(index_freq).cbegin();
+    auto freq = freq_begin;
+    auto index = indexes.begin();
+    while (index != indexes.end()) {
+        for (auto i = 0; i < *freq && index != indexes.end(); ++i) {
+            *index++ = freq - freq_begin;
+        }
+        ++freq;
+    }
+
+
+    // Copy indexes, voltage and current to use for the prototype mechanism
+    typename mechanism_type::iarray indexes_copy(indexes);
+    typename mechanism_type::array  voltage_copy(voltage);
+    typename mechanism_type::array  current_copy(current);
+    typename mechanism_type::array  weights_copy(weights);
+
+    // Create mechanisms
+    auto mech = nest::mc::mechanisms::make_mechanism<mechanism_type>(
+        voltage, current, std::move(weights), std::move(indexes)
+    );
+
+    auto mech_proto = nest::mc::mechanisms::make_mechanism<proto_mechanism_type>(
+        voltage_copy, current_copy,
+        std::move(weights_copy), std::move(indexes_copy)
+    );
+
+    mech_update(dynamic_cast<mechanism_type*>(mech.get()), 10);
+    mech_update(dynamic_cast<proto_mechanism_type*>(mech_proto.get()), 10);
+
+    auto citer = current_copy.begin();
+    for (auto const& c: current) {
+        EXPECT_NEAR(*citer++, c, 1e-6);
+    }
+}
+
+REGISTER_TYPED_TEST_CASE_P(mechanisms, update);
+
+using mechanism_types = ::testing::Types<
+    mechanism_info<
+        nest::mc::mechanisms::hh::mechanism_hh<nest::mc::multicore::backend>,
+        nest::mc::mechanisms::hh_proto::mechanism_hh_proto<nest::mc::multicore::backend>
+   >,
+    mechanism_info<
+        nest::mc::mechanisms::pas::mechanism_pas<nest::mc::multicore::backend>,
+        nest::mc::mechanisms::pas_proto::mechanism_pas_proto<nest::mc::multicore::backend>
+    >,
+    mechanism_info<
+        nest::mc::mechanisms::expsyn::mechanism_expsyn<nest::mc::multicore::backend>,
+        nest::mc::mechanisms::expsyn_proto::mechanism_expsyn_proto<nest::mc::multicore::backend>,
+        true
+    >,
+    mechanism_info<
+        nest::mc::mechanisms::exp2syn::mechanism_exp2syn<nest::mc::multicore::backend>,
+        nest::mc::mechanisms::exp2syn_proto::mechanism_exp2syn_proto<nest::mc::multicore::backend>,
+        true
+    >
+>;
+
+INSTANTIATE_TYPED_TEST_CASE_P(mechanism_types, mechanisms, mechanism_types);
diff --git a/tests/unit/test_synapses.cpp b/tests/unit/test_synapses.cpp
index 0084ed56b281707ff470a8581c58407840e0588b..cd899a5b0fd4890cce0b8c14860340facada0055 100644
--- a/tests/unit/test_synapses.cpp
+++ b/tests/unit/test_synapses.cpp
@@ -153,4 +153,3 @@ TEST(synapses, exp2syn_basic_state)
     EXPECT_NEAR(ptr->A[1], ptr->factor[1]*3.14, 1e-6);
     EXPECT_NEAR(ptr->B[3], ptr->factor[3]*1.04, 1e-6);
 }
-