[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