[CMake] History and ideas behind FindMPI.cmake?
Michael Wild
themiwi at gmail.com
Wed Jan 14 04:42:35 EST 2009
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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PGP.sig
Type: application/pgp-signature
Size: 194 bytes
Desc: This is a digitally signed message part
URL: <http://www.cmake.org/pipermail/cmake/attachments/20090114/dcb638d8/attachment.pgp>
More information about the CMake
mailing list