Repository: spack/spack

Issue:
Unable to build PETSc, PETSC_DIR already set
`configure` fails immediately if the `PETSC_DIR` environment variable is already set. Spack should unset this.
```
===============================================================================
             Configuring PETSc to compile on your system                       
===============================================================================
TESTING: configureExternalPackagesDir from config.framework(/scratch/ajstewart/spack-stage/spack-stage-sFRYcv/petsc-3.7.4/config/BuildSystem/config/framework.py:834)
TESTING: configureDebuggers from config.utilities.debuggers(/scratch/ajstewart/spack-stage/spack-stage-sFRYcv/petsc-3.7.4/config/BuildSystem/config/utilities/debuggers.py:22)
TESTING: configureGit from config.sourceControl(/scratch/ajstewart/spack-stage/spack-stage-sFRYcv/petsc-3.7.4/config/BuildSystem/config/sourceControl.py:24)
TESTING: configureMercurial from config.sourceControl(/scratch/ajstewart/spack-stage/spack-stage-sFRYcv/petsc-3.7.4/config/BuildSystem/config/sourceControl.py:35)
TESTING: configureCLanguage from PETSc.options.languages(/scratch/ajstewart/spack-stage/spack-stage-sFRYcv/petsc-3.7.4/config/PETSc/options/languages.py:27)
TESTING: configureDirectories from PETSc.options.petscdir(/scratch/ajstewart/spack-stage/spack-stage-sFRYcv/petsc-3.7.4/config/PETSc/options/petscdir.py:23)
*******************************************************************************
         UNABLE to CONFIGURE with GIVEN OPTIONS    (see configure.log for details):
-------------------------------------------------------------------------------
The environmental variable PETSC_DIR /home/ajstewart/petsc MUST be the current directory /scratch/ajstewart/spack-stage/spack-stage-sFRYcv/petsc-3.7.4
*******************************************************************************
```


Discussion:
@adamjstewart: Should we just set it to the value it says it has to be (os.getcwd()) in `install()`, and add it to `setup_dependent_environment()` for dependents?
there is already
```
    def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
        # set up PETSC_DIR for everyone using PETSc package
        spack_env.set('PETSC_DIR', self.prefix)
```
~~It probably used to work because `setup_dependent_environment()` was executed for the package itself.~~
just realized that you have it set to something non-Spacky `PETSC_DIR=/home/ajstewart/petsc`, supposedly it works ok when `PETSC_DIR` is empty.
add this to `install()`
```
        # set PETSC_DIR for installation
        # Note that one should set the current (temporary) directory instead
        # its symlink in spack/stage/ !
        os.environ['PETSC_DIR'] = os.getcwd()
```
Is this the difference between `setup_environment` and `setup_dependent_environment`? Should I add `setup_environment`?
@adamjstewart see https://github.com/LLNL/spack/issues/2016#issuecomment-258936647 Another documentation issue :-(
p.s. `setup_dependent_environment()` is for dependencies only, see http://spack.readthedocs.io/en/latest/packaging_guide.html#setup-dependent-environment
`setup_environment` set up *this package's* environment.  `setup_dependent_environment` allows it to put things in the environment of its `dependents`.  so if A depends on B, B can put things in setup_dependent_environment to affect A's environment.

I think you want this change:

```diff
diff --git a/var/spack/repos/builtin/packages/petsc/package.py b/var/spack/repos/builtin/packages/petsc/package.py
index 578349c..ce335ce 100644
--- a/var/spack/repos/builtin/packages/petsc/package.py
+++ b/var/spack/repos/builtin/packages/petsc/package.py
@@ -218,6 +218,7 @@ class Petsc(Package):
                         '-pc_type', 'hypre',
                         '-pc_hypre_type', 'boomeramg')
 
-    def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
-        # set up PETSC_DIR for everyone using PETSc package
+    def setup_environment(self, spack_env, run_env):
+        # set up PETSC_DIR for everyone using PETSc package, and for the build.
         spack_env.set('PETSC_DIR', self.prefix)
+        run_env.set('PETSC_DIR', self.prefix)
```

As the default implementation of `setup_dependent_environment` just calls `setup_environment`.
For those interested, the code that does all this stuff is [in `build_environment.py`, in `setup_package()`](https://github.com/LLNL/spack/blob/develop/lib/spack/spack/build_environment.py#L474), which gets run after forking the build process after every build.

Note the post-oder traversal.  That iterates over all the dependencies before setting up *this* package's environment.

```python
def setup_package(pkg, dirty=False):                                                                                    
    """Execute all environment setup routines."""                                                                       
    spack_env = EnvironmentModifications()                                                                              
    run_env = EnvironmentModifications()                                                                                
                                                                                                                        
    # Before proceeding, ensure that specs and packages are consistent                                                  
    #                                                                                                                   
    # This is a confusing behavior due to how packages are                                                              
    # constructed.  `setup_dependent_package` may set attributes on                                                     
    # specs in the DAG for use by other packages' install                                                               
    # method. However, spec.package will look up a package via                                                          
    # spack.repo, which defensively copies specs into packages.  This                                                   
    # code ensures that all packages in the DAG have pieces of the                                                      
    # same spec object at build time.                                                                                   
    #                                                                                                                   
    # This is safe for the build process, b/c the build process is a                                                    
    # throwaway environment, but it is kind of dirty.                                                                   
    #                                                                                                                   
    # TODO: Think about how to avoid this fix and do something cleaner.                                                 
    for s in pkg.spec.traverse():                                                                                       
        s.package.spec = s                                                                                              
                                                                                                                        
    set_compiler_environment_variables(pkg, spack_env)                                                                  
    set_build_environment_variables(pkg, spack_env, dirty)                                                              
    pkg.architecture.platform.setup_platform_environment(pkg, spack_env)                                                
    load_external_modules(pkg)                                                                                          
    # traverse in postorder so package can use vars from its dependencies                                               
    spec = pkg.spec                                                                                                     
    for dspec in pkg.spec.traverse(order='post', root=False, deptype='build'):                                          
        # If a user makes their own package repo, e.g.                                                                  
        # spack.repos.mystuff.libelf.Libelf, and they inherit from                                                      
        # an existing class like spack.repos.original.libelf.Libelf,                                                    
        # then set the module variables for both classes so the                                                         
        # parent class can still use them if it gets called.                                                            
        spkg = dspec.package                                                                                            
        modules = parent_class_modules(spkg.__class__)                                                                  
        for mod in modules:                                                                                             
            set_module_variables_for_package(spkg, mod)                                                                 
        set_module_variables_for_package(spkg, spkg.module)                                                             
                                                                                                                        
        # Allow dependencies to modify the module                                                                       
        dpkg = dspec.package                                                                                            
        dpkg.setup_dependent_package(pkg.module, spec)                                                                  
        dpkg.setup_dependent_environment(spack_env, run_env, spec)                                                      
                                                                                                                        
    set_module_variables_for_package(pkg, pkg.module)                                                                   
    pkg.setup_environment(spack_env, run_env)                                                                           
                                                                                                                        
    # Make sure nothing's strange about the Spack environment.                                                          
    validate(spack_env, tty.warn)                                                                                       
    spack_env.apply_modifications()    
```
> As the default implementation of setup_dependent_environment just calls setup_environment.

did not know that.
Unfortunately, none of the suggested changes work.

During installation, `PETSC_DIR` must be set to the current directory from which `configure` is run. This is not `self.prefix`. So we will need a separate `setup_environment` and `setup_dependent_environment`.

Getting the current directory isn't so easy though. PETSc is expecting `/scratch/ajstewart/spack-stage/spack-stage-SnQEin/petsc-3.7.4`. Here is what the following return:

`os.getcwd()` in setup_environment:
`/blues/gpfs/home/software/spack-0.10.0`

`self.stage.path`:
`/blues/gpfs/home/software/spack-0.10.0/var/spack/stage/petsc-3.7.4-2wq3at7rf2z374pd6ppibyna2idltsee`

So unless there is some other way, I think I'll just try unsetting it.
@adamjstewart try in install (see above https://github.com/LLNL/spack/issues/2767#issuecomment-271030405)
```
        # set PETSC_DIR for installation
        # Note that one should set the current (temporary) directory instead
        # its symlink in spack/stage/ !
        os.environ['PETSC_DIR'] = os.getcwd()
```
this/similar is already done in SLEPC and **does** work.
Yes, that seems to work. Do we like this solution better than unsetting it? If it is already in use then I'm fine with it.
> Do we like this solution better than unsetting it? If it is already in use then I'm fine with it.

i think there is no harm to set it to what it actually should be for all current versions of PETSc, IIRC.

Resolving patch:
diff --git a/var/spack/repos/builtin/packages/petsc/package.py b/var/spack/repos/builtin/packages/petsc/package.py
--- a/var/spack/repos/builtin/packages/petsc/package.py
+++ b/var/spack/repos/builtin/packages/petsc/package.py
@@ -218,6 +218,16 @@ def install(self, spec, prefix):
                         '-pc_type', 'hypre',
                         '-pc_hypre_type', 'boomeramg')
 
+    def setup_environment(self, spack_env, run_env):
+        # configure fails if these env vars are set outside of Spack
+        spack_env.unset('PETSC_DIR')
+        spack_env.unset('PETSC_ARCH')
+
+        # Set PETSC_DIR in the module file
+        run_env.set('PETSC_DIR', self.prefix)
+        run_env.unset('PETSC_ARCH')
+
     def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
-        # set up PETSC_DIR for everyone using PETSc package
+        # Set up PETSC_DIR for everyone using PETSc package
         spack_env.set('PETSC_DIR', self.prefix)
+        spack_env.unset('PETSC_ARCH')


Test patch: