[CMake] History and ideas behind FindMPI.cmake?

Bartlett, Roscoe A rabartl at sandia.gov
Wed Jan 14 12:16:07 EST 2009


Michael,

You make good points.

I will look into the Module you list below.

Thanks,

- Ross
 

> -----Original Message-----
> From: Michael Wild [mailto:themiwi at gmail.com] 
> Sent: Wednesday, January 14, 2009 2:43 AM
> To: Bartlett, Roscoe A
> Cc: cmake at cmake.org
> Subject: Re: [CMake] History and ideas behind FindMPI.cmake?
> 
> 
> On 13. Jan, 2009, at 15:17, Bartlett, Roscoe A wrote:
> >
> > In Trilinos, an MPI configured build creates all MPI 
> executables (in 
> > some sense).  Also, most Trilinos software is set up to 
> automatically 
> > check to see if MPI is initialized or not and will run correctly in 
> > serial mode with MPI enabled but not initialized.
> >
> > Also, most newer MPI implementations that I have used allow you to 
> > build with MPI support but never call MPI_Init(...) and 
> never have to 
> > use mpiexec/mpirun in order to run a serial executable (as 
> long as you 
> > don't call MPI functions).  That is how you can get away 
> with defining 
> > CMAKE_[C,CXX,Fortran]_COMPILER as the MPI compiler 
> wrappers.  Also, if 
> > you only use try_compile(...) tests at configure time, then 
> you will 
> > never have any problem with this.  Even with try_run(...), 
> as long as 
> > these tests don't call MPI functions then they should work 
> just fine 
> > also with most newer MPI implementations.
> >
> > Lastly, our project Trilinos does not really define *any* 
> executables 
> > except for tests and examples.  To set up even single- process 
> > tests/examples to work with MPI is trivial.  There is a 
> single object 
> > that you have to create in main(...) like:
> >
> >  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
> >
> > and you just have to run the test/example with 
> mpirun/mpiexec with one 
> > process in case your MPI implementation requires that you do so.
> >
> > The C++ class Teuchos::GlobalMPISession works with both MPI 
> and non- 
> > MPI enabled software.
> 
> That might be true for Trilinos, but not necessarily for 
> other projects. I can easily imagine a project where the main 
> executable/ library is built using MPI, but some 
> helper/utility programs are not.  
> There is no point in linking them against MPI. This not only 
> makes startup slower, but also increases memory footprint. In 
> some cases it might even be harmful.
> 
> >
> >
> >>> 4) The standard MPI install structure of many MPI implementations 
> >>> (e.g. MPICH, OpenMPI, LAM MPI etc.) of prefix/[include,
> >> bin] will be
> >>> exploited and searching from MPI_BASE_DIR (which is set by the
> >>> client) will be done.  In this way, you can just set a 
> single cache 
> >>> variable on most systems and get MPI totally set up.
> >>
> >> This won't work at all. See the --includedir and --libdir 
> options of 
> >> the OpenMPI configure script. Your proposal will force 
> these values 
> >> to the default, making too many assumptions.
> >
> > You misunderstood.  This would not require that MPI must be 
> installed 
> > in PREFIX/[include, bin, lib] but if it is, then the user 
> could just 
> > give the base directory.  It is not hard to set this up at 
> all and I 
> > am surprised that the other CMake find modules don't do this.  
> > However, if we are going to just use mpicc/mpiCC/mpiC++/
> > mpif77 etc and mpirun/mpiexec then we just need the 'bin' directory 
> > and can thrown the rest of this out.
> 
> 
> It's not necessary. The user can define CMAKE_PREFIX_PATH and 
> this has the effect you want.
> 
> 
> >
> >
> >>> These days, I don't know if anyone still uses raw compilers
> >> and then
> >>> tries to manually pass in the compiler options and link
> >> libraries.
> >>> We can still support such a thing but I think this is the
> >> 1% exception
> >>> instead of the rule.  Am I wrong about this?
> >>
> >> I know of at least one large project which does not use 
> the wrappers 
> >> because the developers abstracted the communications into separate 
> >> libraries, one for MPI, one for GAMMA and one for LVM. The 
> user has 
> >> then the choice of which library should be used when he starts the 
> >> program. Couldn't do that with your proposal.
> >
> > Is this a runtime option or a configure-time option in this "large 
> > project"?  If it is a runtime option, then you have to at 
> least build 
> > in support for MPI so using the MPI compiler wrappers is 
> just fine.  
> > If it is a configure-time option, then you can configure with and 
> > without MPI.  That is exactly what Trilinos does.  You can build a 
> > serial version of Trilinos with and without MPI.  If there was some 
> > other great communication layer we could also wrap that and 
> use that 
> > with most of Trilinos (most of Trilinos uses thin abstract adapters 
> > for communication and is not directly tied to MPI).
> 
> It is a runtime option. Before you start a solver you can 
> choose which implementation of the communications library you 
> want. One of the reasons I don't like linking against all 
> possible parallel communications libraries is our 
> heterogeneous cluster. On some compute nodes PVM is 
> available, but not MPI and vice versa. There are also 
> differenc MPI implementations around (OpenMPI, Quadrics, 
> etc.) The queueing system automagically submits the job to 
> the right queue.  
> Problem is now, that if e.g. everything is linked against 
> OpenMPI but is submitted to a queue where only PVM or 
> Quadrics MPI is installed, the program won't even start.
> 
> If you really want to use an MPI compiler for everything, 
> then you could use the following FindMpiCompilers.cmake 
> module I came up with:
> 
> # - Find the MPI compiler wrappers
> # This module locates the MPI compiler wrappers (mpicc, mpicxx/mpic++,
> mpif77 and mpif90).
> # It is useful if one wants to force a project to use the MPI 
> compiler wrappers as default # compilers.
> #
> # The module has the following COMPONENTS:
> #  C    searches for mpicc
> #  CXX  searches for mpicxx and mpic++
> #  F77  searches for mpif77
> #  F90  searches for mpif90
> # If no components are specified, all of them are enabled by default.
> #
> # The module sets the following cache variables (if the 
> corresponding module is enabled):
> #  MPICOMPILERS_C    the mpicc compiler
> #  MPICOMPILERS_CXX  the mpicxx/mpic++ compiler #  
> MPICOMPILERS_F77  the mpif77 compiler #  MPICOMPILERS_F90  
> the mpif90 compiler # # If the user wishes to specify a 
> specific compiler wrapper (e.g. one which is # using a 
> non-standard name or one which is not found on the path) can 
> do so # by setting the corresponding MPICOMPILERS_XXX 
> variable (e.g. using the # -D flag the first time CMake is 
> run). It also honours environment variables # by the same 
> name. The CC, CXX and similar variables are not considered by 
> # design.
> #
> # If the module is not REQUIRED make sure to check the 
> MPICOMPILERS_XXX # variables.
> #
> # Beware that although the module can search for both the 
> mpif77 and mpif90 # compiler wrappers, CMake only knows the 
> CMAKE_Fortran_COMPILER variable # which means that you can't 
> use both of the wrappers in the same project. This, # 
> however, probably is not a big issue as Fortran90 is a 
> superset of # Fortran77 and all Fortran90 compilers I know of 
> also process Fortran77 # sources.
> #
> # An example CMakeLists.txt could look like this:
> #
> #  # prevent CMake from compiler detection using NONE as the 
> project language #  project( some_project NONE ) # #  
> cmake_minimum_required( VERSION 2.6 ) # #  # find the mpi 
> compiler wrappers #  find_package( MpiCompilers REQUIRED CXX 
> F77 ) # #  # set the CMAKE_XXX_COMPILER variables #  set( 
> CMAKE_CXX_COMPILER ${MPICOMPILERS_CXX} ) #  set( 
> CMAKE_Fortran_COMPILER ${MPICOMPILERS_F77} ) #  # enable the 
> corresponding languages to do the compiler detection #  
> enable_language( CXX ) #  enable_language( Fortran ) # #  # 
> now go on as usual #  add_executable( fancy_mpi_program 
> source1.cxx source2.f )
> 
> # Copyright 2009 Michael Wild <themiwi at users.sourceforge.net>
> 
> # check the components that are requested if( 
> MpiCompilers_FIND_COMPONENTS )
>    set( __MpiCompilers_C FALSE )
>    set( __MpiCompilers_CXX FALSE )
>    set( __MpiCompilers_F77 FALSE )
>    set( __MpiCompilers_F90 FALSE )
>    foreach( __MpiCompilers_comp ${MpiCompilers_FIND_COMPONENTS} )
>      if( __MpiCompilers_comp STREQUAL C )
>        set( __MpiCompilers_C TRUE )
>      elseif( __MpiCompilers_comp STREQUAL CXX )
>        set( __MpiCompilers_CXX TRUE )
>      elseif(__MpiCompilers_comp STREQUAL F77 )
>        set( __MpiCompilers_F77 TRUE )
>      elseif( __MpiCompilers_comp STREQUAL F90 )
>        set( __MpiCompilers_F90 TRUE )
>      else( __MpiCompilers_comp STREQUAL C )
>        message( FATAL_ERROR "Unknown component 
> ${__MpiCompilers_comp}" )
>      endif( __MpiCompilers_comp STREQUAL C )
>    endforeach( __MpiCompilers_comp )
> else( MpiCompilers_FIND_COMPONENTS )
>    # by default turn all components on
>    set( __MpiCompilers_C TRUE )
>    set( __MpiCompilers_CXX TRUE )
>    set( __MpiCompilers_F77 TRUE )
>    set( __MpiCompilers_F90 TRUE )
> endif( MpiCompilers_FIND_COMPONENTS )
> 
> # find the requested compilers and set up the list # of 
> required variables set( __MpiCompilers_REQVARS "" ) set( 
> __MpiCompilers_FOUNDCOMPILERS "" ) if( __MpiCompilers_C )
>    if( NOT "$ENV{MPICOMPILERS_C}" STREQUAL "" )
>      set( MPICOMPILERS_C $ENV{MPICOMPILERS_C} CACHE FILEPATH 
> "Path to the MPI C compiler" )
>    else( NOT "$ENV{MPICOMPILERS_C}" STREQUAL "" )
>      find_program( MPICOMPILERS_C mpicc DOC "Path to the MPI 
> C compiler" )
>    endif( NOT "$ENV{MPICOMPILERS_C}" STREQUAL "" )
>    list( APPEND __MpiCompilers_REQVARS MPICOMPILERS_C )
>    set( __MpiCompilers_FOUNDCOMPILERS "$ 
> {__MpiCompilers_FOUNDCOMPILERS} ${MPICOMPILERS_C}" ) endif( 
> __MpiCompilers_C ) if( __MpiCompilers_CXX )
>    if( NOT "$ENV{MPICOMPILERS_CXX}" STREQUAL "" )
>      set( MPICOMPILERS_CXX $ENV{MPICOMPILERS_CXX} CACHE 
> FILEPATH "Path to the MPI C++ compiler" )
>    else( NOT "$ENV{MPICOMPILERS_CXX}" STREQUAL "" )
>      find_program( MPICOMPILERS_CXX NAMES mpicxx mpic++ DOC 
> "Path to the MPI C++ compiler" )
>    endif( NOT "$ENV{MPICOMPILERS_CXX}" STREQUAL "" )
>    list( APPEND __MpiCompilers_REQVARS MPICOMPILERS_CXX )
>    set( __MpiCompilers_FOUNDCOMPILERS "$ 
> {__MpiCompilers_FOUNDCOMPILERS} ${MPICOMPILERS_CXX}" ) endif( 
> __MpiCompilers_CXX ) if( __MpiCompilers_F77 )
>    if( NOT "$ENV{MPICOMPILERS_F77}" STREQUAL "" )
>      set( MPICOMPILERS_F77 $ENV{MPICOMPILERS_F77} CACHE 
> FILEPATH "Path to the MPI F77 compiler" )
>    else( NOT "$ENV{MPICOMPILERS_F77}" STREQUAL "" )
>      find_program( MPICOMPILERS_F77 mpif77 DOC "Path to the 
> MPI F77 compiler" )
>    endif( NOT "$ENV{MPICOMPILERS_F77}" STREQUAL "" )
>    list( APPEND __MpiCompilers_REQVARS MPICOMPILERS_F77 )
>    set( __MpiCompilers_FOUNDCOMPILERS "$ 
> {__MpiCompilers_FOUNDCOMPILERS} ${MPICOMPILERS_F77}" ) endif( 
> __MpiCompilers_F77 ) if( __MpiCompilers_F90 )
>    if( NOT "$ENV{MPICOMPILERS_F90}" STREQUAL "" )
>      set( MPICOMPILERS_F90 $ENV{MPICOMPILERS_F90} CACHE 
> FILEPATH "Path to the MPI F90 compiler" )
>    else( NOT "$ENV{MPICOMPILERS_F90}" STREQUAL "" )
>      find_program( MPICOMPILERS_F90 mpif90 DOC "Path to the 
> MPI F77 compiler" )
>    endif( NOT "$ENV{MPICOMPILERS_F90}" STREQUAL "" )
>    list( APPEND __MpiCompilers_REQVARS MPICOMPILERS_F90 )
>    set( __MpiCompilers_FOUNDCOMPILERS "$ 
> {__MpiCompilers_FOUNDCOMPILERS} ${MPICOMPILERS_F90}" ) endif( 
> __MpiCompilers_F90 )
> 
> mark_as_advanced( ${__MpiCompilers_REQVARS} )
> 
> # handle standard arguments
> include( FindPackageHandleStandardArgs ) 
> find_package_handle_standard_args( MpiCompilers DEFAULT_MSG 
> __MpiCompilers_FOUNDCOMPILERS ${__MpiCompilers_REQVARS} )
> 
> >
> >
> > The argument for directly using the MPI compiler wrappers is  
> > compelling (and that is why almost everyone I know uses them).
> 
> Yes, for simple projects. NOT for mixed projects.
> 
> Michael
> 


More information about the CMake mailing list