diff --git a/packages/dune/package.py b/packages/dune/package.py
index 8c12511..88b913d 100644
--- a/packages/dune/package.py
+++ b/packages/dune/package.py
@@ -41,6 +41,58 @@ class Dune(CMakePackage):
       ("master" , "master"),
     ]
 
+    # This defines the mapping of the variant names for Dune modules and the
+    # resource names that we assign later on.
+    dune_variants_to_resources = {
+        'alugrid' : 'dune-alugrid',
+        'codegen' : 'dune-codegen',
+        'fem' : 'dune-fem',
+        'foamgrid' : 'dune-foamgrid',
+        'functions': 'dune-functions',
+        'gridglue' : 'dune-grid-glue',
+        'multidomaingrid' : 'dune-multidomaingrid',
+        'pdelab' : 'dune-pdelab',
+        'polygongrid' : 'dune-polygongrid',
+        'spgrid' : 'dune-spgrid',
+        'testtools' : 'dune-testtools',
+        'typetree' : 'dune-typetree',
+        'uggrid' : 'dune-uggrid',
+    }
+
+    # Define the inverse mapping
+    dune_resources_to_variants = {v: k for k, v in dune_variants_to_resources.items()}
+
+    # Dependencies between modules - not necessarily the full set
+    # as the closure of module dependencies is built later on.
+    # dune-common does not need to be named.
+    module_dependencies = {
+        'dune-alugrid': ['dune-grid'],
+        'dune-codegen': ['dune-pdelab', 'dune-testtools', 'dune-alugrid'],
+        'dune-fem': ['dune-grid'],
+        'dune-fempy': ['dune-fem'],
+        'dune-foamgrid': ['dune-grid'],
+        'dune-functions': ["dune-grid", "dune-typetree", "dune-localfunctions", "dune-istl"],
+        'dune-grid': ['dune-geometry'],
+        'dune-grid-glue': ['dune-grid'],
+        'dune-localfunctions': ['dune-geometry'],
+        'dune-multidomaingrid': ['dune-grid', 'dune-typetree'],
+        'dune-pdelab': ['dune-istl', 'dune-functions'],
+        'dune-polygongrid': ['dune-grid'],
+    }
+
+    # Build the closure of above module dependency list
+    for module in module_dependencies:
+        closure = set(module_dependencies[module])
+        old_closure = set()
+        while (len(closure) > len(old_closure)):
+            old_closure = closure.copy()
+
+            for res in old_closure:
+                for mod in module_dependencies.get(res, []):
+                    closure.add(mod)
+
+        module_dependencies[module] = list(closure)
+
     # Variants for the general build process
     variant('shared', default=True, description='Enables the build of shared libraries.')
 
@@ -68,25 +120,16 @@ class Dune(CMakePackage):
     # Some variants that were here that are on my todo list
     # variant('jupyter', default=False, description='Build with Jupyter support')
 
-    # Define one variant for each Dune module that we have. Only core modules
-    # are activated by default.
-    variant('alugrid', default=False, description='Build with dune-alugrid module')
-    variant('codegen', default=False, description='Build with dune-codegen module')
-    variant('fem', default=False, description='Build with dune-fem(py) module')
-    variant('foamgrid', default=False, description='Build with dune-foamgrid module')
-    variant('functions', default=False, description='Build with dune-functions module')
-    variant('geometry', default=True, description='Build with dune-geometry module')
-    variant('grid', default=True, description='Build with dune-grid module')
-    variant('gridglue', default=False, description='Build with dune-grid-glue module')
-    variant('istl', default=True, description='Build with dune-istl module')
-    variant('localfunctions', default=True, description='Build with dune-localfunctions module')
-    variant('multidomaingrid', default=False, description='Build with dune-multidomaingrid module')
-    variant('pdelab', default=False, description='Build with dune-pdelab module')
-    variant('polygongrid', default=False, description='Build with dune-polygongrid module')
-    variant('spgrid', default=False, description='Build with dune-spgrid module')
-    variant('testtools', default=False, description='Build with dune-testtools module')
-    variant('typetree', default=False, description='Build with dune-typetree module')
-    variant('uggrid', default=False, description='Build with dune-uggrid module')
+    # Define one variant for each non-core Dune module that we have.
+    for var, res in dune_variants_to_resources.items():
+        variant(var, default=False, description='Build with the %s module' % res)
+
+    # Define conflicts between Dune module variants. These conflicts are of the following type:
+    # conflicts('dune~functions', when='+pdelab') -> dune-pdelab cannot be built without dune-functions
+    for var, res in dune_variants_to_resources.items():
+        for dep in module_dependencies.get(res, []):
+            if dep in dune_resources_to_variants:
+                conflicts('dune~%s' % dune_resources_to_variants[dep], when='+%s' % var)
 
     # Iterate over all available Dune versions and define resources for all Dune modules
     # If a Dune module behaves differently for different versions (e.g. dune-python got
@@ -98,28 +141,28 @@ class Dune(CMakePackage):
             name='dune-geometry',
             git='https://gitlab.dune-project.org/core/dune-geometry.git',
             branch=branch,
-            when='@%s+geometry' % vers,
+            when='@%s' % vers,
         )
 
         resource(
             name='dune-grid',
             git='https://gitlab.dune-project.org/core/dune-grid.git',
             branch=branch,
-            when='@%s+grid' % vers,
+            when='@%s' % vers,
         )
 
         resource(
             name='dune-istl',
             git='https://gitlab.dune-project.org/core/dune-istl.git',
             branch=branch,
-            when='@%s+istl' % vers,
+            when='@%s' % vers,
         )
 
         resource(
             name='dune-localfunctions',
             git='https://gitlab.dune-project.org/core/dune-localfunctions.git',
             branch=branch,
-            when='@%s+localfunctions' % vers,
+            when='@%s' % vers,
         )
 
         resource(
@@ -232,29 +275,7 @@ class Dune(CMakePackage):
         submodules=True,
     )
 
-    # Dependencies between modules - not necessarily the full set
-    # as the closure of module dependencies is built later on.
-    module_dependencies = {}
-    module_dependencies["dune-alugrid"] = ["dune-grid", "dune-geometry", "dune-common"]
-    module_dependencies["dune-codegen"] = ["dune-pdelab", "dune-testtools", "dune-alugrid"]
-    module_dependencies["dune-common"] = []
-    module_dependencies["dune-fem"] = ["dune-grid"]
-    module_dependencies["fune-fempy"] = ["dune-fem"]
-    module_dependencies["dune-foamgrid"] = ["dune-grid"]
-    module_dependencies["dune-functions"] = ["dune-grid", "dune-typetree", "dune-localfunctions", "dune-istl"]
-    module_dependencies["dune-geometry"] = ["dune-common"]
-    module_dependencies["dune-grid"] = ["dune-common", "dune-geometry"]
-    module_dependencies["dune-grid-glue"] = ["dune-grid"]
-    module_dependencies["dune-istl"] = ["dune-common"]
-    module_dependencies["dune-localfunctions"] = ["dune-common", "dune-geometry"]
-    module_dependencies["dune-multidomaingrid"] = ["dune-grid", "dune-typetree"]
-    module_dependencies["dune-pdelab"] = ["dune-common", "dune-grid", "dune-istl", "dune-functions"]
-    module_dependencies["dune-polygongrid"] = ["dune-grid"]
-    module_dependencies["dune-python"] = ["dune-common"]
-    module_dependencies["dune-testtools"] = ["dune-common"]
-    module_dependencies["dune-typetree"] = ["dune-common"]
-    module_dependencies["dune-uggrid"] = ["dune-common"]
-
+    # Make sure that Python components integrate well into Spack
     extends('python')
     python_components = [ 'dune' ]
 
@@ -280,13 +301,9 @@ class Dune(CMakePackage):
     depends_on('python@3.0:', type=('build', 'run'))
     depends_on('py-setuptools', type='build', when='+python')
     depends_on('py-numpy', type=('build', 'run'), when='+python')
-    depends_on('py-pip', type=('build', 'run'), when='+codegen')
-    depends_on('py-pip', type=('build', 'run'), when='+python')
-    depends_on('py-pip', type=('build', 'run'), when='+testtools')
+    depends_on('py-pip', type=('build', 'run'))
     depends_on('py-sphinx', type=('build', 'run'), when='+doc')
-    depends_on('py-wheel', type='build', when='+codegen')
-    depends_on('py-wheel', type='build', when='+python')
-    depends_on('py-wheel', type='build', when='+testtools')
+    depends_on('py-wheel', type='build')
     depends_on('scotch+mpi', when='+ptscotch')
     depends_on('sionlib', when='+sionlib')
     depends_on('suite-sparse', when='+suitesparse')
@@ -297,9 +314,8 @@ class Dune(CMakePackage):
 
     # Apply patches
     patch('virtualenv_from_envvariable.patch', when='+testtools')
-    patch('virtualenv_from_envvariable.patch', when='+codegen')
 
-    # Some conflicts
+    # Some additional variant conflicts of Dune modules and upstream dependencies
     conflicts('dune~superlu', when='+codegen')
 
     def setup_build_environment(self, env):
@@ -356,7 +372,7 @@ class Dune(CMakePackage):
             '-DCMAKE_DISABLE_FIND_PACKAGE_ZOLTAN:BOOL=%s' % nvariant_bool('+zoltan'),
         ]
 
-        if '+testtools' in spec or '+codegen' in spec:
+        if '+testtools' in spec:
             cmake_args.append('-DDUNE_PYTHON_VIRTUALENV_SETUP:BOOL=ON')
             cmake_args.append('-DDUNE_PYTHON_ALLOW_GET_PIP:BOOL=ON')
             cmake_args.append('-DDUNE_PYTHON_VIRTUALENV_PATH:STRING="%s"' % join_path(Path.home(), '.cache', 'dune-python-env', self.spec.dag_hash()))
@@ -370,34 +386,6 @@ class Dune(CMakePackage):
 
         return cmake_args
 
-    def module_dependency_closure(self, when, reslist):
-        # Get a list of all modules that share the version requirement
-        all_resources = []
-        for w, rl in self.resources.items():
-            if w.version == when.version:
-                all_resources.extend(rl)
-
-        # And build the closure of modules from the given reslist
-        closure = set(reslist)
-        old_closure = set()
-        while (len(closure) > len(old_closure)):
-            old_closure = closure.copy()
-
-            for res in old_closure:
-                for mod in self.module_dependencies.get(res.name, []):
-                    for r in all_resources:
-                        if r.name == mod:
-                            closure.add(r)
-
-        return list(closure)
-
-    def _get_needed_resources(self):
-        # Modify the list of resources by building a transitive closure of Dune module dependencies.
-        self.resources = {when: self.module_dependency_closure(when, reslist) for when, reslist in self.resources.items()}
-
-        # and call the original implementation
-        return CMakePackage._get_needed_resources(self)
-
     def cmake(self, spec, prefix):
         # dune-codegen delivers its own set of patches for its submodules
         # that we can apply with a script delivered by dune-codegen.