11

我有一个 C++ 代码,可以根据某个预处理器标志使用 MPI 支持进行编译;缺少适当的标志,源编译为非并行版本。

我想设置 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 在编译启用 MPI 的程序版本时它必须使用 $(MPICXX) 而不是 $(CXX) ?

4

6 回答 6

7

我有同样的问题,我发现没有真正好的方法可以让自动工具有条件地将 MPI 编译器用于特定目标。Autotools 擅长根据您的源代码编写的语言(CCCXXFCF77等)确定要使用的编译器,但它确实不善于确定是否将 MPI 编译器用于特定目标。您可以设置 MPICC、MPICXX 等,但如果您以这种方式使用编译器,则基本上必须为您的目标重写所有 Makefile 规则(如上所述)。如果你这样做了,那么写一个 automake 文件有什么意义呢?

其他人建议像使用外部库一样使用 MPI,这是我提倡的方法,但您不应该手动执行,因为不同的 MPI 安装具有传递给编译器的不同标志集,它们可以依赖您正在编译的语言。

好消息是我所知道的所有当前发布的 MPI 编译器都支持自省参数,比如-show,-show-compile-show-link. 您可以自动从脚本中提取参数。

因此,我处理这个问题的方法是制作一个m4脚本,从 MPI 编译器中提取定义、包含、库路径、库和链接器标志,然后将它们分配给您可以在Makefile.am. 这是脚本:

lx_find_mpi.m4

这使得 MPI 以 automake 期望的方式工作。顺便说一句,这是 CMake 在他们的FindMPI模块中使用的方法,我发现它在那里工作得很好。它使构建更加方便,因为您可以为您的目标做这样的事情:

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_find_mpi.m4还设置了一些 shell 变量,以便您可以在configure.ac文件中测试是否找到了 MPI。例如,如果您正在寻找 MPI C++ 支持,您可以测试$have_CXX_mpi宏是否找到它。

我已经使用mvapichOpenMPI测试了这个宏,以及BlueGene机器上的自定义MPICH2实现(尽管它没有解决您将在那里看到的所有交叉编译问题)。让我知道如果有什么不起作用。我想保持宏尽可能健壮。

于 2010-10-19T21:13:10.683 回答
5

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

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)
于 2012-07-26T19:58:38.440 回答
2

如果您禁用了subdir-objectsto 选项automake,则可能会出现以下情况:

配置.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])

生成文件.am:

SUBDIRS =
if ENABLE_SEQ
SUBDIRS += seq
endif
if ENABLE_MPI
SUBDIRS += mpi
endif

来源.am:

ALL_SOURCES = src/foo.c src/bar.cc src/baz.cpp

序列/Makefile.am:

include $(top_srcdir)/sources.am

bin_PROGRAMS = seq
seq_SOURCES = $(ALL_SOURCES)

mpi/Makefile.am:

include $(top_srcdir)/sources.am

CXX = $(MPICXX)
AM_CPPFLAGS = -DWITH_MPI

bin_PROGRAMS = mpi
mpi_SOURCES = $(ALL_SOURCES)

阻止您在同一目录中执行这两项操作的唯一方法是覆盖$(CXX). 例如,您可以设置mpi_CPPFLAGSautomake优雅地处理它,但是编译器开关在这里禁止它。

于 2010-10-19T20:52:37.850 回答
1

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

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
于 2011-01-14T17:39:05.283 回答
1

这是我为构建两个静态库而提出的解决方案 - 一个带有 MPI ( libmylib_mpi.a),一个没有 ( libmylib.a)。这种方法的优点是不需要重复的源文件、两个变体的单个 Makefile.am 以及使用子目录的能力。您应该能够根据需要修改它以生成二进制文件而不是库。我像往常一样构建非 MPI 库,然后对于 MPI 变体,我将其_SOURCES留空并改为使用,为目标文件_LIBADD指定扩展名。.mpi.o然后我指定一个规则来使用 MPI 编译器生成 MPI 目标文件。

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

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

配置.ac:

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

进行条件检查的方法可能比我在此处列出的更有效(欢迎提出建议)。

生成文件.am:

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
于 2017-10-15T20:04:47.463 回答
0

MPI 安装确实(通常)附带编译器包装器,但不要求您使用它们——MPI 并不坚持这样做。如果您想走自己的路,您可以编写自己的 makefile 以确保 C++ 编译器获得正确的库(等)。要找出正确的库(等)是什么,请检查编译器包装器,在我使用的所有系统上,它是一个 shell 脚本。

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

于 2010-10-19T13:26:20.433 回答