Подтвердить что ты не робот

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

У меня есть код на С++, который можно скомпилировать с поддержкой MPI в зависимости от определенный флаг препроцессора; отсутствует соответствующий флаг, источники скомпилировать в непараллельную версию.

Я хотел бы настроить Makefile.am так, чтобы он компилировал как MPI-параллельная и последовательная версия, если есть возможность ./configure.

Здесь catch: MPI имеет собственную CML-компиляторную оболочку и настаивает что источники скомпилированы и связаны с ним, а не стандартными С++. Если бы я сам написал Makefile, мне пришлось бы сделайте что-нибудь вроде этого:

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

myprog.mpi: myprog.cxx
    $(MPICXX) -DWITH_MPI ... myprog.cxx

Есть ли способ сказать automake, что он должен использовать $(MPICXX) вместо из $(CXX) при компиляции версии программы с поддержкой MPI?

4b9b3361

Ответ 1

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

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

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

Итак, что я сделал, чтобы сделать это, нужно сделать m4 script, который извлекает из компиляторов MPI определения, включает в себя пути библиотек, библиотеки libs и компоновщика, затем присваивает их переменным, которые вы можете использовать в вашем Makefile.am. Здесь script:

lx_find_mpi.m4

Это заставляет MPI работать так, как ожидает автомат. Кстати, это подход 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 С++, вы можете протестировать $have_CXX_mpi, чтобы узнать, нашел ли макрос.

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

Ответ 2

Мне жаль, что использование automake MPI настолько сложно. Я много лет пытаюсь найти хорошее решение. У меня есть исходное дерево, в котором есть одна библиотека, а затем много программ в подпапках, которые используют библиотеку. Некоторые из папок - это программы mpi, но когда я пытаюсь заменить CXX на компилятор MPI, используя Makefile.am.

if USE_MPI
  MPIDIR = $(MPICOMPILE)
  MPILIB = $(MPILINK)
  [email protected]@
  [email protected]@
  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)

Ответ 3

Если вы отключили опцию subdir-objects до automake, возможно, что-то вроде этого:

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])

Makefile.am:

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

sources.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)

МПИ/Makefile.am:

include $(top_srcdir)/sources.am

CXX = $(MPICXX)
AM_CPPFLAGS = -DWITH_MPI

bin_PROGRAMS = mpi
mpi_SOURCES = $(ALL_SOURCES)

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

Ответ 4

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

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

Ответ 5

Вот решение, которое я придумал для создания двух статических библиотек: один с 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
    ...

configure.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

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

Makefile.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,[email protected]) -o [email protected]

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

Ответ 6

Установка MPI (обычно) поставляется с обертками компилятора, но нет необходимости использовать их - MPI не настаивает на этом. Если вы хотите пойти своим путем, вы можете написать свой собственный make файл, чтобы убедиться, что компилятор С++ получает нужные библиотеки (и т.д.). Чтобы выяснить, что представляют собой правильные библиотеки (и т.д.), Проверьте оболочку компилятора, которая есть на всех системах, которые я использовал, оболочку script.

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