Hi Kenneth,

On 16/10/2014, at 7:29 am, Kenneth Hoste <[email protected]> wrote:

> Hi Ben,
> 
> On 15/10/14 03:17, Ben Roberts wrote:
>> Hi list,
>> 
>> I’m trying to install Amber 12 with Easybuild. My current version of the 
>> framework is the latest checkout of the “develop” branch from git: commit 
>> 3c4976c5f0ea5dad572f6ed3c014380b299e2d7a.
>> 
>> I’m having trouble because the Amber installation process, being inherently 
>> non-standard, is interacting strangely with the Easybuild process.
>> 
>> An overview of the Amber build process is as follows:
>> 
>> 1. Download and extract the Amber tarball (extracts to “amber12”)
>> 2. Download and extract the AmberTools tarball (also extracts into “amber12”)
>> 3. Change into the “amber12” directory
>> 4. Set the AMBERHOME environment variable to the amber12 directory
>> 5. Run “configure” with options for a serial build
>> 6. Run “make install” — note that this combines the functionality of “make” 
>> and “make install” into a single step, and builds AmberTools and Amber in 
>> situ
>> 7. Run “make test”
>> 8. Run “make clean” to delete serial-specific object files, etc.
>> 9. Run “configure” again with options for a parallel build
>> 10. Run “make install”
>> 11. Run “make test.parallel”
>> 12. Run “make clean”
>> 13. Run “configure” again with options for a CUDA build
>> 14. Run “make install”
>> 15. Run “make test.cuda”
>> 16. Optionally, run “make clean”
>> 
>> I’ve attached my easyconfig and easyblock for your information.
>> 
>> The particular issue I’m having is the interplay of three features of this 
>> build. One is that the build and install directories are the same, so that 
>> I’ve used the “buildininstalldir” option in my easyconfig. The other is that 
>> it’s necessary to keep at least some parts of the serial installation around 
>> for parallel and CUDA builds, so that deleting the install directory between 
>> builds is not an option. The third is the use of multiple configure calls, 
>> to reflect the staged nature of the build.
>> 
>> You can probably already see where I’m going with this, which is the method 
>> “make_builddir” in easybuild-framework/easybuild/framework/easyblock.py. 
>> This method, if “buildininstalldir” is set, will force a “cleanupoldbuild” 
>> and veto a “keeppreviousinstall” (line 641ff.), regardless of any options to 
>> the contrary that I set in the easyconfig.
>> 
>> How can I get around this? Is there an option that can be implemented to 
>> deal with staged builds of this sort, the prospect of overloading the 
>> make_builddir method in my easyblock, or some other solution that I haven’t 
>> floated yet?
> Since you already have a dedicated easyblock for Amber, you should push as 
> much as possible in there, and keep Amber easyconfigs absolutely minimal.
> That is: move defining the configure options and test targets in the 
> easyblock, set self.build_in_installdir = True in the easyblock (see the WRF 
> easyblock for example),  move the custom sanity check to the easyblock, etc.
> 
> Combining a custom easyblock together with the support for using a list of 
> strings for configopts/buildopts/installopts (rather a single string) is 
> indeed tricky, and the build_in_installdir requirements isn't exactly helping 
> either.
> Basically, it boils down to the observation that Amber doesn't fit the 
> step-wise approach for configure/build/install that EasyBuild uses...
> 
> Here's what I would do: leave both the configure_step and install_step empty 
> in the easyblock for Amber, and run the whole procedure in the build_step 
> (or, alternatively, in the install_step, and leave the build_step empty). 
> Since only the configure options and the test command are different, you can 
> probably implement this as a simple for-loop.
> 
> For example (totally untested, but it should give you an idea):
> 
> ### START of untested build_step implementation for Amber
> 
> # define $AMBERHOME and move to right subdirectory for build
> amber_dir = os.path.join(self.installdir, 'amber%s' % self.version)
> env.setvar('AMBERHOME', amber_dir)
> try:
>    os.chdir(amber_dir)
> except OSError, err:
>    self.log.error("Failed to change to %s: %s" % (amber_dir, err))
> 
> # make sure $LIBS is unset, since it may break the build
> if 'LIBS' in os.environ:
>    del os.environ['LIBS']
> 
> # set required environment variables
> 
> # note: what if another BLAS/LAPACK lib is used?
> imkl_root = get_software_root('imkl')
> if imkl_root:
>    env.setvar('MKL_HOME', imkl_root)
> 
> # note: not sure if this would also work with MPI libs other than impi?
> for mpilib in ['impi', 'OpenMPI', 'MVAPICH2', 'MPICH2']:
>    mpi_root = get_software_root(mpilib)
>    if mpi_root:
>        env.setvar('MPI_HOME', mpi_root)
> 
> # list of common configure options, including dependency-specific options
> common_configopts = ["--no-updates"]
> netcdf_root = get_software_root('netCDF')
> if netcdf_root:
>    common_configopts.append("--with-netcdf %s" % netcdf_root)
> python_root = get_software_root('Python')
> if python_root:
>    common_configopts.append("--with-python %s" % os.path.join(python_root, 
> 'bin', 'python'))
> 
> # hardcoded for Intel compilers, what if another compiler is used?
> # use self.toolchain.comp_family(), compare with toolchain.INTELCOMP, 
> toolchain.GCC, etc?
> config_target = "intel"
> 
> # list of make targets + corresponding test target
> targets = [('', 'test')]
> if self.toolchain.options.get('usempi', None):
>    targets.append(('-mpi', 'test.parallel'))
> cuda_root = get_software_root('CUDA')
> if cuda_root:
>    env.setvar('CUDA_HOME', cuda_root)
>    targets.append(('-cuda', 'test.cuda'))
> 
> # configure/build/test/clean for each target
> for target_configopt, target_test in targets:
>    # configure
>    self.cfg['configopts'] = ' '.join(common_configopts + [target_configopt, 
> config_target])
>    super(EB_Amber, self).configure_step()
>    # build (in-situ) using 'make install'
>    super(EB_Amber, self).install_step()
>    # make test
>    self.cfg['runtest'] = target_test
>    super(EB_Amber, self).test_step()
>    # make clean
>    self.cfg['buildopts'] = 'clean'
>    super(EB_Amber, self).build_step()
> 
> ### END of untested build_step implementation for Amber
> 
> Other remarks:
> 
> * Name the easyblock class 'EB_Amber' rather than 'Amber', that way EB will 
> auto-determine it should use that based on the software name.
> * I'm not sure what you're trying to achieve with the self.already_extracted 
> check in extract_step? This seemsto mean the 2nd source file will not be 
> unpacked, is that what you're aiming for?
> * The patchlevels should be part of the versionsuffix somehow, to distinguish 
> between Amber builds with different patch levels?
> * What's the problem with the currently commented out code in 
> make_module_extra?
> 
> Don't hesitate to ask further questions. Maybe it's worthwhile to set up a 
> conf call to discuss this further at some point (if the time of the day is 
> decent on both ends ;-)), let me know.

Thanks for your prompt and helpful response! Right now, I can’t remmeber the 
answers to all your other remarks, but I’ve renamed the class EB_Amber, the 
patch levels are in the version suffix of the EasyConfig, and the rest of the 
code has got the point where it “works for me”. I’m happy to take any specific 
questions either here, or in the context of the pull requests I’ve put in for 
it.

Best regards,
Ben

Reply via email to