как скомпилировать MPI и не-MPI версии одной и той же программы с automake?

у меня есть код 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, что он должен использовать $(MPICXX) вместо этого $(CXX) при компиляции версии программы с поддержкой MPI?

6 ответов


у меня такая же проблема, и я обнаружил, что нет действительно хорошего способа получить autotools в условно используйте компиляторы MPI для определенных целей. Autotools хорошо разбирается в том, какой компилятор использовать на основе языка, на котором написан ваш источник (CC, CXX, FC, F77, etc.), но на самом деле не очень хорошо понять, использовать ли компилятор MPI для определенной цели. Вы можете установить MPICC, MPICXX и т. д. но вы по сути переписать все правила Makefile для вашей цели (как вы сделали выше), если вы используете компилятор таким образом. Если вы это сделаете, какой смысл писать файл automake?

кто-то еще предложил использовать MPI как внешнюю библиотеку, и это подход, который я бы рекомендовал, но вы не должны делать это вручную, потому что разные установки MPI имеют разные наборы флагов, которые они передают компилятору, и они могут зависеть от языка, который вы компилируете.

хорошая вещь это все компиляторы MPI, которые я знаю, поддерживают аргументы интроспекции, такие как -show, -show-compile или -show-link. Вы можете автоматически извлекать аргументы из сценариев.

Итак, то, что я сделал, чтобы справиться с этим, было сделать m4 сценарий, который извлекает определяет, включает, пути библиотеки, libs и флаги компоновщика из компиляторов 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 также устанавливает некоторые переменные оболочки, чтобы вы могли проверить в своем configure.ac файл, был ли найден MPI. например, если вы ищете поддержку MPI c++, вы можете проверить $have_CXX_mpi чтобы узнать, нашел ли его макрос.

я протестировал этот макрос с mvapich и openmpi с, а также на заказ MPICH2 реализация на BlueGene машины (хотя он не решает все проблемы кросс-компиляции, которые вы увидите там). Дайте мне знать, если что-то не работает. Я хотел бы сохранить макрос как можно более надежным.


мне жаль, что использование MPI automake так сложно. Я боролся с этим в течение многих месяцев пытается найти хорошее решение. У меня есть исходное дерево, в котором есть одна библиотека, а затем много программ в подпапках, которые используют библиотеку. Некоторые из папок являются программами mpi, но когда я пытаюсь заменить CXX компилятором MPI, используя in 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)

если вы отключили до 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])

make-файл.ам:

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

сл/make-файл.ам:

include $(top_srcdir)/sources.am

bin_PROGRAMS = seq
seq_SOURCES = $(ALL_SOURCES)

ЛПУ/make-файл.ам:

include $(top_srcdir)/sources.am

CXX = $(MPICXX)
AM_CPPFLAGS = -DWITH_MPI

bin_PROGRAMS = mpi
mpi_SOURCES = $(ALL_SOURCES)

единственное, что мешает вам делать оба из них в одном каталоге, это переопределение $(CXX). Вы могли бы, например,mpi_CPPFLAGS и automake будет обработайте это изящно,но переключатель компилятора делает его здесь невозможным.


возможным обходным путем для не использования различных источников может быть:

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

для Automake:

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 (libmylib_mpi.a) и один без (libmylib.a). Преимущество этого метода заключается в том, что нет необходимости дублировать исходные файлы в один файл Makefile.я за оба варианта, и возможность использовать подкаталоги. Вы должны иметь возможность изменять это по мере необходимости для создания двоичного файла вместо библиотеки. Я создаю библиотеку без MPI как обычно, а затем для варианта MPI я оставляю _SOURCES пустая и использовать , указание расширения .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

вероятно, есть более эффективный способ сделать условную проверку, чем я перечислил здесь (я приветствую предложения).

make-файл.ам:

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 (обычно) поставляются с оболочками компилятора, но нет требования, чтобы вы их использовали -- MPI does не настаивать на этом. Если вы хотите пойти своим путем, вы можете написать свой собственный makefile, чтобы убедиться, что компилятор C++ получает правильные библиотеки (и т. д.). Чтобы выяснить, что такое правильные библиотеки (etc), проверьте оболочку компилятора, которая во всех системах, которые я использовал, является скриптом оболочки.

на первый взгляд обертки компилятора, которые поставляются с такие продукты, как компиляторы Intel, немного сложны, но остановитесь и подумайте о том, что происходит-вы просто компилируете программу, которая использует внешнюю библиотеку или две. Написать makefile для использования библиотек MPI не сложнее, чем написать makefile для использования любой другой библиотеки.