Как скомпилировать 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?
Ответы
Ответ 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 файл для использования любой другой библиотеки.