如何使用automake编译同一程序的MPI和非MPI版本? 我有一个C++代码,可以根据MPI支持编译,这取决于 某些预处理器标志;缺少相应的标志,源 编译为非并行版本

如何使用automake编译同一程序的MPI和非MPI版本? 我有一个C++代码,可以根据MPI支持编译,这取决于 某些预处理器标志;缺少相应的标志,源 编译为非并行版本,mpi,autoconf,automake,Mpi,Autoconf,Automake,我想设置Makefile.am,以便它编译 MPI并行版本和顺序版本,如果选择 给出了/configure 这里有个注意事项:MPI有自己的C++编译器包装器,并坚持 源代码是使用它而不是标准来编译和链接的 C++编译器。如果我要自己编写Makefile,我必须 这样做: myprog.seq: myprog.cxx $(CXX) ... myprog.cxx myprog.mpi: myprog.cxx $(MPICXX) -DWITH_MPI ... myprog.cxx

我想设置Makefile.am,以便它编译 MPI并行版本和顺序版本,如果选择 给出了
/configure

这里有个注意事项:MPI有自己的C++编译器包装器,并坚持 源代码是使用它而不是标准来编译和链接的 C++编译器。如果我要自己编写Makefile,我必须 这样做:

myprog.seq: myprog.cxx
    $(CXX) ... myprog.cxx

myprog.mpi: myprog.cxx
    $(MPICXX) -DWITH_MPI ... myprog.cxx
有没有办法告诉automake它必须改用$(MPICXX)呢 在编译启用MPI的程序版本时,是否使用$(CXX)?

MPI安装(通常)附带编译器包装,但不要求您使用它们--MPI不坚持使用。如果您想按自己的方式编写自己的Mag文件,以确保C++编译器获得正确的库(ETC)。为了弄清楚什么是正确的库(etc),请检查编译器包装器,在我使用的所有系统上,它都是一个shell脚本


乍一看,英特尔编译器等产品附带的编译器包装有点让人望而生畏,但停下来想想到底发生了什么——你只是在编译一个利用一两个外部库的程序。编写makefile以使用MPI库并不比编写makefile以使用任何其他库更困难。

如果禁用了
自动生成
子对象
选项,类似的操作可能会起作用:

configure.ac:

AC_ARG_ENABLE([seq], ...)
AC_ARG_ENABLE([mpi], ...)
AM_CONDITIONAL([ENABLE_SEQ], [test $enable_seq = yes])
AM_CONDITIONAL([ENABLE_MPI], [test $enable_mpi = yes])
AC_CONFIG_FILES([Makefile seq/Makefile mpi/Makefile])
AC_INIT()
AC_PROG_RANLIB
AC_LANG(C++)
AC_PROG_CXX
# test for MPI, define MPICXX, etc. variables, and define HAVE_MPI as a condition that will evaluate to true if MPI is available and false otherwise.
AX_MPI([AM_CONDITIONAL([HAVE_MPI], [test "1" = "1"])],[AM_CONDITIONAL([HAVE_MPI], [test "1" = "2"])]) #MPI optional for xio
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
Makefile.am:

SUBDIRS =
if ENABLE_SEQ
SUBDIRS += seq
endif
if ENABLE_MPI
SUBDIRS += mpi
endif
include $(top_srcdir)/sources.am

bin_PROGRAMS = seq
seq_SOURCES = $(ALL_SOURCES)
include $(top_srcdir)/sources.am

CXX = $(MPICXX)
AM_CPPFLAGS = -DWITH_MPI

bin_PROGRAMS = mpi
mpi_SOURCES = $(ALL_SOURCES)
AUTOMAKE_OPTIONS = subdir-objects
lib_LIBRARIES = libmylib.a
libmylib_a_SOURCES = src/mylib_1.cpp src/mylib_2.cpp ...

#conditionally generate libmylib_mpi.a if MPI is available
if HAVE_MPI
    lib_LIBRARIES += libmylib_mpi.a
    libmylib_mpi_a_SOURCES = #no sources listed here
    #use LIBADD to specify objects to add - use the basic filename with a .mpi.o extension
    libmylib_mpi_a_LIBADD = src/mylib_1.mpi.o src/mylib_2.mpi.o ...
endif
AM_CPPFLAGS = -I${srcdir}/include

include_HEADERS = include/mylib.h

# define a rule to compile the .mpi.o objects from the .cpp files with the same name
src/%.mpi.o: ${srcdir}/src/%.cpp ${srcdir}/include/mylib.h
    $(MPICXX)  $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -DWITH_MPI=1 -c $(patsubst %.mpi.o,$(srcdir)/%.cpp,$@) -o $@

#define a rule to clean the .mpi.o files
clean-local:
    -rm -f src/*.mpi.o
来源:www.am.com:

ALL_SOURCES = src/foo.c src/bar.cc src/baz.cpp
seq/Makefile.am:

SUBDIRS =
if ENABLE_SEQ
SUBDIRS += seq
endif
if ENABLE_MPI
SUBDIRS += mpi
endif
include $(top_srcdir)/sources.am

bin_PROGRAMS = seq
seq_SOURCES = $(ALL_SOURCES)
include $(top_srcdir)/sources.am

CXX = $(MPICXX)
AM_CPPFLAGS = -DWITH_MPI

bin_PROGRAMS = mpi
mpi_SOURCES = $(ALL_SOURCES)
AUTOMAKE_OPTIONS = subdir-objects
lib_LIBRARIES = libmylib.a
libmylib_a_SOURCES = src/mylib_1.cpp src/mylib_2.cpp ...

#conditionally generate libmylib_mpi.a if MPI is available
if HAVE_MPI
    lib_LIBRARIES += libmylib_mpi.a
    libmylib_mpi_a_SOURCES = #no sources listed here
    #use LIBADD to specify objects to add - use the basic filename with a .mpi.o extension
    libmylib_mpi_a_LIBADD = src/mylib_1.mpi.o src/mylib_2.mpi.o ...
endif
AM_CPPFLAGS = -I${srcdir}/include

include_HEADERS = include/mylib.h

# define a rule to compile the .mpi.o objects from the .cpp files with the same name
src/%.mpi.o: ${srcdir}/src/%.cpp ${srcdir}/include/mylib.h
    $(MPICXX)  $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -DWITH_MPI=1 -c $(patsubst %.mpi.o,$(srcdir)/%.cpp,$@) -o $@

#define a rule to clean the .mpi.o files
clean-local:
    -rm -f src/*.mpi.o
mpi/Makefile.am:

SUBDIRS =
if ENABLE_SEQ
SUBDIRS += seq
endif
if ENABLE_MPI
SUBDIRS += mpi
endif
include $(top_srcdir)/sources.am

bin_PROGRAMS = seq
seq_SOURCES = $(ALL_SOURCES)
include $(top_srcdir)/sources.am

CXX = $(MPICXX)
AM_CPPFLAGS = -DWITH_MPI

bin_PROGRAMS = mpi
mpi_SOURCES = $(ALL_SOURCES)
AUTOMAKE_OPTIONS = subdir-objects
lib_LIBRARIES = libmylib.a
libmylib_a_SOURCES = src/mylib_1.cpp src/mylib_2.cpp ...

#conditionally generate libmylib_mpi.a if MPI is available
if HAVE_MPI
    lib_LIBRARIES += libmylib_mpi.a
    libmylib_mpi_a_SOURCES = #no sources listed here
    #use LIBADD to specify objects to add - use the basic filename with a .mpi.o extension
    libmylib_mpi_a_LIBADD = src/mylib_1.mpi.o src/mylib_2.mpi.o ...
endif
AM_CPPFLAGS = -I${srcdir}/include

include_HEADERS = include/mylib.h

# define a rule to compile the .mpi.o objects from the .cpp files with the same name
src/%.mpi.o: ${srcdir}/src/%.cpp ${srcdir}/include/mylib.h
    $(MPICXX)  $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -DWITH_MPI=1 -c $(patsubst %.mpi.o,$(srcdir)/%.cpp,$@) -o $@

#define a rule to clean the .mpi.o files
clean-local:
    -rm -f src/*.mpi.o

唯一阻止您在同一目录中执行这两项操作的是重写
$(CXX)
。例如,您可以设置
mpi\CPPFLAGS
automake
来优雅地处理这个问题,但是编译器开关在这里是不允许的。

我也有同样的问题,我发现没有真正好的方法让自动工具有条件地为特定目标使用mpi编译器。Autotools擅长根据源代码所用的语言来确定使用哪种编译器(
CC
CXX
FC
F77
,等等),但它确实不擅长确定是否为特定目标使用MPI编译器。您可以设置MPICC、MPICXX等,但如果您以这种方式使用编译器,则必须为目标重写所有Makefile规则(如上所述)。如果你这么做了,写一个汽车制造文件有什么意义

还有人建议像使用外部库一样使用MPI,这是我提倡的方法,但您不应该手工操作,因为不同的MPI安装有不同的标志集,它们传递给编译器,并且可能取决于您正在编译的语言

好的是,据我所知,目前所有上市的MPI编译器都支持内省参数,如
-show
-show compile
-show link
。您可以自动从脚本中提取参数

因此,我所做的是制作一个
m4
脚本,从MPI编译器中提取定义、包含、库路径、libs和链接器标志,然后将它们分配给可以在
Makefile.am
中使用的变量。以下是脚本:

这使得MPI按照汽车制造商的预期工作。顺便说一句,这是CMake在他们的模块中使用的方法,我发现它在那里非常有效。它使构建更加方便,因为您可以为您的目标执行如下操作:

bin_PROGRAMS = mpi_exe seq_exe

# This is all you need for a sequential program
seq_exe_SOURCES = seq_exe.C

# For an MPI program you need special LDFLAGS and INCLUDES
mpi_exe_SOURCES = mpi_exe.C
mpi_exe_LDFLAGS = $(MPI_CXXLDFLAGS)

INCLUDES = $(MPI_CXXFLAGS)
其他语言也有类似的标志,因为正如我所说的,特定的标志和库可能因您使用的语言MPI编译器而异

lx\u find\u mpi.m4
还设置了一些shell变量,以便您可以在
configure.ac
文件中测试是否找到了mpi。例如,如果您正在寻找MPI C++支持,可以测试<代码> $HaveCxXMP.MP/<代码>查看宏是否找到了。
我已经用和测试了这个宏,并在机器上测试了自定义实现(尽管它没有解决您将在那里看到的所有交叉编译问题)。如果出现问题,请告诉我。我希望尽可能保持宏的健壮性。

不使用不同源的一个可能的解决方法是:

myprog.seq: myprog.cxx
    $(CXX) ... myprog.cxx

myprog-mpi.cxx: myprog.cxx
    @cp myprog.cxx myprog-mpi.cxx

myprog.mpi: myprog-mpi.cxx
    $(MPICXX) -DWITH_MPI ... myprog-mpi.cxx
    @rm -f myprog-mpi.cxx
对于汽车制造商:

myprog-bin_PROGRAMS = myprog-seq myprog-mpi

myprog_seq_SOURCES = myprog.c

myprog-mpi.c: myprog.c
    @cp myprog.c myprog-mpi.c

myprog_mpi_SOURCES = myprog-mpi.c
myprog_mpi_LDFLAGS = $(MPI_CXXLDFLAGS)

INCLUDES = $(MPI_CXXFLAGS)
BUILT_SOURCES = myprog-mpi.c
CLEANFILES = myprog-mpi.c

我很抱歉,让汽车制造商使用MPI是如此困难。为了找到一个好的解决方案,我已经为此奋斗了好几个月。我有一个源代码树,它有一个库,然后在使用库的子文件夹中有许多程序。有些文件夹是mpi程序,但当我尝试使用
Makefile.am
中的mpi编译器替换CXX时

if USE_MPI
  MPIDIR = $(MPICOMPILE)
  MPILIB = $(MPILINK)
  CXX=@MPICXX@
  F77=@MPIF77@
  MPILIBS=$(MPILINK)
endif
我明白了

CXX was already defined in condition TRUE, which includes condition USE_MPI ...
configure.ac:12: ... `CXX' previously defined here
我没有指定编译器的规则,所以也许有一种方法可以做到这一点

SUBDIRS = .
bin_PROGRAMS = check.cmr
check_ccmr_SOURCES = check_gen.cpp
check_ccmr_CXXFLAGS = -I$(INCLUDEDIR) $(MPIDIR)
check_ccmr_LDADD = -L$(LIBDIR)
check_ccmr_LDFLAGS = $(MPILIB)

下面是我为构建两个静态库而提出的解决方案—一个带有MPI(
libmylib\u MPI.a
),另一个没有(
libmylib.a
)。这种方法的优点是,不需要重复的源文件,两个变体都需要一个Makefile.am,并且可以使用subdir。您应该能够根据需要修改它,以生成二进制文件而不是库。我按照正常方式构建非MPI库,然后对于MPI变体,我将
\u SOURCES
保留为空,并使用
\u LIBADD
,为对象文件指定扩展名
.MPI.o
。然后,我指定一个规则来使用MPI编译器生成MPI对象文件

总体文件/目录结构类似于

configure.ac
Makefile.am
src
    mylib1.cpp
    mylib2.cpp
    ...
include
    mylib.h
    ...
configure.ac:

AC_ARG_ENABLE([seq], ...)
AC_ARG_ENABLE([mpi], ...)
AM_CONDITIONAL([ENABLE_SEQ], [test $enable_seq = yes])
AM_CONDITIONAL([ENABLE_MPI], [test $enable_mpi = yes])
AC_CONFIG_FILES([Makefile seq/Makefile mpi/Makefile])
AC_INIT()
AC_PROG_RANLIB
AC_LANG(C++)
AC_PROG_CXX
# test for MPI, define MPICXX, etc. variables, and define HAVE_MPI as a condition that will evaluate to true if MPI is available and false otherwise.
AX_MPI([AM_CONDITIONAL([HAVE_MPI], [test "1" = "1"])],[AM_CONDITIONAL([HAVE_MPI], [test "1" = "2"])]) #MPI optional for xio
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
可能有一种比我在这里列出的更有效的方法来进行条件检查(我很好