Skip to content

Compiling Help For CMake

Lori A. Burns edited this page May 27, 2015 · 5 revisions
####Table of Contents 1. [Introduction](#Introduction) 2. [Define Variables](#Define Variables) 3. [Compilation Commands](#Compilation Commands) 4. [Troubleshooting](#Troubleshooting) 1. [Undefined References](#UndRef) 2. [General Advice](#GenAdv) ## Introduction [Return to top](#Top)

Psi4 private currently only supports Cross Platform make (i.e. cmake). The purpose of this wiki is largely to help install Psi4 with cmake.

If everything is in the standard places, and you want Psi4 to be installed in standard places, the build should go off without a hitch. Of course in 99.9% of cases, life isn't that simple and likely you suffer from problems associated with "intelligently" designed systems such as: having include files in /usr/lib, libraries in /tmp, you don't have root access, or... Regardless of why you can't just do (a normal CMake build):

mkdir build
cd build
../configure.cmake 
make
make install

this wiki is here to help you.

Before we start, let me give you my personal recommendation, which is to create a bash script (or whatever scripting language/shell you want) for the commands that follow, so that as you get further in the build, you do not have to remember how you solved previous problems. Additionally, it makes it very easy to replicate your build if something goes wrong. I will assume you have taken this advice, are using bash, and are in a Linux like environment. However, I am not using any super tricky bash commands, so you should be able to translate, via inspection, to whatever language you prefer. Perhaps someone more versed in compiling in other operating systems can add comments pertaining to how the instructions change for those things.

All of the Psi4 files live in some directory, which we term the top-level directory, or the root directory ${PSI_ROOT}. Your compilation script I'm going to guide you through should live just inside this directory. For the purposes of this guide assume you called it ${PSI_ROOT}/install.sh. The basic outline of this script will be set some variables, make a build directory, and then call the appropriate build commands.

##Define Variables [Return to top](#Top)

The very first thing you should worry about is your compiler. Psi4 is written entirely in C and C++; however, due to interfacing issues with BLAS/LAPACK, or if you are compiling ERD, you may/will need a Fortran compiler as well. If you can find your C and C++ compilers, the Fortran one should be there too, so for simplicity just get the Fortran one while you are there. Likely you have such compilers in /usr/bin and CMake will find them by default. On a Linux box these default compilers will be gcc, g++, and gfortran; however, if you don't want to use these compilers because you, for example, have access to the Intel compilers (which produce way faster binaries), or maybe you want to use the MPI wrappers (you really do want to start doing this or you will be missing out on lots of awesomeness) you will need to specify the compiler. Regardless start a script, and add something like this to it:

#!/bin/sh

#
#This is ${PSI_ROOT}/install.sh, an install script for installing
#Psi4 with CMake
#
#Assuming we don't want gcc,g++, or gfortran we need to set these
#The C compiler
CCOMP=/path/to/C/Compiler
#The C++ compiler
CPPCOMP=/path/to/C++/Compiler
#The Fortran compiler
FORTCOMP=/path/to/Fortran/Compiler

of course you should replace these (and the paths in following code blocks) with the ones for your machine.

All script commands are assumed to be in the same file as the one you just started, so I will not keep reprinting what is already in the file, just what you should be adding at each step. Now let's worry about where do you want Psi4 to install the basis sets, python scripts, executables, and other goodies to? By default this will be /usr/local/psi. I will call this ${PSI_PREFIX}, so add

#Where the final executables, basis sets, etc. go
PSI_PREFIX=/path/to/psiprefix

Next, let's worry about Boost. Psi4 uses Boost pretty intimately, and will build Boost for you if it can't find Boost, thus this step is only required if Psi4 fails to build Boost for you (highly unlikely) or you already have Boost installed on your system and are paranoid about space (or more likely, want to use that version because it is highly optimized for your architecture already, like by the supercomputer you are building on). Note some relatively new features of Boost are required for building Psi4 so make sure your Boost version is at least equal to the one included in Psi4 (1.55 at the time of writing).

A Boost installation is typically setup with some top level directory, which we call ${BOOST_ROOT}. Inside ${BOOST_ROOT} is then typically a directory: ${BOOST_ROOT}/lib and a directory ${BOOST_ROOT}/include/boost. For the former case that whole path will be your ${BOOST_LIB} variable, whereas for the latter only ${BOOST_ROOT}/include will be your boost include path

#Only needed if we are not letting Psi build Boost
BOOST_ROOT=/path/to/top/directory/of/Boost
BOOST_LIB=${BOOST_ROOT}/lib
BOOST_INC=${BOOST_ROOT}/include

Next, let's worry about BLAS and LAPACK. If you are using Intel compilers these both fall under MKL. The actual Psi4 configure flags want the command as it will be written on the compiler line. In particular if you are using MKL (probably also for other BLAS distributions as well) note that there will typically be two options for all of these, one for 32-bit architectures and one for 64-bit architectures, make sure you choose the appropriate one. Again we need the includes and the libraries:

BLAS_LIB="-L/path/to/blas/lib -lblas -libs -lto -llink -lagainst"

#If your blas lib is mkl uncomment this line:
#BLAS_LIB="-L/path/to/mkl -mkl"
BLAS_INC=/path/to/blas/include
LAPACK_LIB="-L/path/to/lapack/lib -llapack -libs -lto -link -lagainst"
#If your lapack lib is mkl uncomment this line:
#LAPACK_LIB=${BLAS_LIB}
LAPACK_INC=/path/to/lapack/include

Finally, we need to a version of Python to link against. Likely you will have one in /usr/bin/ that will be appropriate, but if that one is too old, or you just want to use a different one, set that here. This time we need an executable, libraries, and includes. My python distribution actually installs the includes into a sub directory of include/python2.7, unlike Boost, we need to grab the python2.7 part in this case. For the libraries it creates a directory lib/python2.7, but the main python library (libpython2.7.so) is actually not in that subdirectory but in lib/ so we do not include the python2.7 part of lib/python2.7.

PYTHON_EXE=/path/to/python/executable
PYTHON_LIB=/path/to/python/lib
PYTHON_INC=/path/to/python/includes
##Compilation Commands [Return to top](#Top)

Now we just need the actual compile commands in our script. CMake enforces the good coding practice of using a build directory, to keep the source tree clean. Thus we need to make a so-called build directory that will contain our objects, and is not ${PSI_ROOT}. Typically this is instead a subdirectory named build or something more descriptive. Let's call it build:

BUILD_DIR=build

#If our build directory does not exist make it
if [ ! -d ${BUILD_DIR} ]; then
   mkdir ${BUILD_DIR}
fi

There is a nice wrapper for the CMake command, that takes a configure like syntax, and sets the CMake run up for us. Note that there are a few minor syntax changes from the old configure that was used with GNU make. The biggest change is that if your BLAS/LAPACK distribution is not one library, you are stuck passing the BLAS library as a linker flag. Our script looks like:

#Switch to the build directory
cd ${BUILD}
#This is all of our includes
ALLINCS="-I${BLAS_INC} -I${LAPACK_INC} -I${PYTHON_INC}"
ALLLIBS="${BLAS_LIB} -L${PYTHON_LIB}"
#Set our python environment variable
export PYTHON="${PYTHON_EXE}"
#Run the generated configure file with our choosen options
#Note "\" characters allow bash commands to be split across lines 
#for easier reading

#The Last line is the recommended Psi4 optimization flags
#Only include flags for things you actually set!!!
#Also don't pass compilers if you just want the defaults
../configure.cmake --prefix="${PSI_PREFIX}" \
             --with-cc="${CCOMP}" \
             --with-cxx="${CPPCOMP}" \
             --with-f77="${FORTCOMP}" \
             --with-boost-incdir="${BOOST_INC}" \
             --with-boost-libdir="${BOOST_LIB}" \
             --with-lapack="${LAPACK_LIB}" \
             --with-cxxflags="${ALLINCS}" \
             --with-ldflags="${ALLLIBS}" \
             --with-python="${PYTHON_EXE}" \
             --with-opt
#Of course configuration will go off without a hitch so we now
#go ahead and make, make install (-j N means using N processors FYI)
make -j 6
make -j 6 install
##Troubleshooting [Return to top](#Top)

See: CMakeFAQ

### Undefined References [Return to top](#Top)

Unfortunately one of the "wonderful" things about supporting two builds is that people usually only worry about using one or the other. This means if I add some great feature and only make sure Psi4 compiles with this great feature under GNU make, I have very likely broken the cmake build, and vice versa. Both builds need to know about new directories and source files and failing to tell them about these changes breaks them (Depending on the code in the various CMakeLists.txt and Makefile.in files they may be tolerant off this to an extent). The point being as code is developed, it is increasingly common that the build systems will break. In fact at the time of this writing, the cmake build had been broken.

Typically such breaks will manifest as undefined references at linking. If you get such a problem locate the source code file that contains the reference. Then add it to the appropriate file. To do this, lets say src/lib/libunicorn/libunicorn.cc now contains an undefined reference to void shootrainbows(), which is contained in file unicorn.cc. If the build is not finding the libunicorn directory then make sure src/lib/CMakeLists.txt contains:

add_subdirectory(libunicorn)

and src/lib/Makefile.in contains:

subdirs = libint \
                  libderiv \
      <lots of other libraries that already exist>
          libunicorn

then in src/lib/libunicorn/CMakeLists.txt find the line that looks like:

set(SRC sourcefile1.cc sourcefile2.cc ...)

and add unicorn.cc to it. In src/lib/libunicorn/Makefile.in check for a line like:

TRUECXXSRC = $(notdir $(wildcard $(srcdir)/*.cc))

if you find this line you are good because it is a wildcard matching pattern that automatically adds all source files with extension ".cc". If instead there is a list of source files, like:

TRUECXXSRC = pony.cc cuddle.cc <other source files>

simply add unicorn.cc to the list.