2014-01-24 3 views
3

Я новичок в PETSc. У меня большой код C++, и я хочу добавить PETSc в некоторые из файлов, которые у меня уже есть, поэтому мне нужно изменить свой make-файл так, чтобы он мог скомпилировать PETSc.Использование PETSc в make-файле в пределах моего пользовательского make-файла

Возможно ли иметь два разных файла makefile, а затем вызвать PETSc makefile в моем собственном файле makefile? если да, то как я могу это сделать?

Есть ли у кого-нибудь опыт связывания PETSc с собственным кодом?

Кстати, я использую Linux в качестве операционной системы.

+0

Вы хотите, чтобы ваша сборка создавала PETSc, а также создавала код или вы хотите, чтобы ваш код использовал уже построенный PETSc? –

+0

Да, я хочу, чтобы моя сборка построила PETSc, а также построила код – Nazi

+0

Возможно, но это немного сложно. Систему makefile PETSc трудно понять. – Dan

ответ

1

Я столкнулся с той же проблемой, и для этого я сделал простой, но всеобъемлющий makefile (для использования в ОС Linux). Предположим, что код хранится в ex_1.cpp. Предполагается, что PETSc устанавливается в /usr/local/petsc/petsc-3.7.4. После установки PETSc можно найти правильные переменные окружения в файле configure.log.

можно затем использовать следующую makefile скомпилировать и связать C++ код:

# PETSC 3.7.4 Makefile (Linux) 
#---------------------------------------- 

# NOTE: look up `configure.log` in PETSc folder to obtain 
# the proper environmental parametres 
PETSC_DIR=/usr/local/petsc/petsc-3.7.4 
PETSC_ARCH=arch-linux2-c-debug 
PETSC_CONFIGDIR=${PETSC_DIR}/lib/petsc/ 

include ${PETSC_CONFIGDIR}/conf/variables 
include ${PETSC_CONFIGDIR}/conf/rules 
include ${PETSC_CONFIGDIR}/conf/test 

# compile and link options 
LOCDIR= ./ 
DIRS = 
CXX_STD = -std=c++11 
CXX_CFLAGS = ${CXX_STD} ${CXX_FLAGS} ${PETSC_CCPPFLAGS} 
LIBS = ${PETSC_LIB} 
CXX_LFLAGS = ${CXX_STD} 

#OBJS = $(SRC1:.cpp=.o) 
#---------------------------------------- 

.PHONY: default allclean run_1 

default: chkopts 
    @echo "--- PETSC CONFIGURATION -----------------" 
    @if [ "${CUDAC}" != "" ]; then \ 
     echo "Using CUDA compile: ${PETSC_CUCOMPILE}";\ 
    fi 
    @echo "Using C/C++ linker: ${PCC_LINKER}" 
    @echo "Using C/C++ flags: ${PCC_LINKER_FLAGS}" 
    @echo "Using C++ flags: ${CXX_FLAGS}" 
    @echo "-----------------------------------------" 
    @echo "Using libraries: ${PETSC_LIB}" 
    @echo "-----------------------------------------" 
    @echo "Using mpiexec: ${MPIEXEC}" 
    @echo "=========================================" 

ex_1: default ex_1.o 
    @echo "---- LINK -----" 
    ${CXX} -w -o ex_1.out ex_1.o ${LIBS} ${CXX_LFLAGS} 
    -${RM} ex_1.o 
    @echo "===============" 

ex_1.o: 
    @echo "--- COMPILE ---" 
    ${CXX} -o ex_1.o -c ex_1.cpp ${CXX_CFLAGS} 
    @echo "===============" 

run_1: 
    @echo "===============" 
    @echo "--- EXECUTE ---" 
    @echo "starting on `hostname` at `date`" 
    @echo "machine characteristics: `uname -a`" 
    @echo "===============" 
    ${MPIEXEC} -n 1 ./ex_1.out #-info 
    @echo "===============" 

allclean: clean 
    [email protected]${RM} *.out 

Заметьте, что chkopts и clean правила уже определены PETSc. Исполняемый файл будет сохранен как ex_1.out. Чтобы скомпилировать и связать код, используйте make ex_1 и для запуска исполняемого файла используйте make run_1.

2

Я не слишком хорошо знаком с Make-файлами, поэтому я бы просто перечислил метод «взлома». Мы рассмотрим метод «взлома» в этом тексте позже. У меня есть Makefile и пример исходного кода ex1.cpp, который использует несколько массивов PETSc, векторов, функций вместе с моим собственным регулярным массивом C/C++, который выполняет обмен данными с массивом и векторами PETSc. Это можно рассматривать как миниатюрную версию вашего дела.

Мой Makefile -

PETSC_DIR=/usr/local/petsc 

include ${PETSC_DIR}/conf/variables 
include ${PETSC_DIR}/conf/rules 
include ${PETSC_DIR}/conf/test 

CLINKER=g++ 

ex1 : ex1.o chkopts 
    ${CLINKER} -w -o ex1 ex1.o ${PETSC_LIB} 
    ${RM} ex1.o 
    ./ex1 

Конечно вам нужно редактировать PETSC_DIR в папку, PETSc в вашей системе. Ввод «make ex1» будет компилировать и связывать исходный код для создания исполняемого файла и его выполнения.

После я «сделать EX1» на моей системе, два процесса выхода компиляции и компоновки показаны, которые перечислены здесь следующим образом:

Компиляция -

/usr/local/petsc/arch-linux2-c-debug/bin/mpicc -o ex1.o -c -fPIC -Wall -Wwrite-strings -Wno-strict-aliasing -Wno-unknown-pragmas -g3 -fno-inline -O0 -I/usr/local/petsc/include -I/usr/local/petsc/arch-linux2-c-debug/include ex1.cpp

Linking -

g++ -w -o ex1 ex1.o -Wl,-rpath,/usr/local/petsc/arch-linux2-c-debug/lib -L/usr/local/petsc/arch-linux2-c-debug/lib -lpetsc -Wl,-rpath,/usr/local/petsc/arch-linux2-c-debug/lib -lflapack -lfblas -lX11 -lpthread -lm -Wl,-rpath,/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -Wl,-rpath,/usr/lib/x86_64-linux-gnu -L/usr/lib/x86_64-linux-gnu -Wl,-rpath,/lib/x86_64-linux-gnu -L/lib/x86_64-linux-gnu -lmpichf90 -lgfortran -lm -lgfortran -lm -lquadmath -lm -lmpichcxx -lstdc++ -ldl -lmpich -lopa -lmpl -lrt -lpthread -lgcc_s –ldl

Таким образом, «хитрость» заключается в том, что вы запускаете Makefile и разделяете выходы процесса компиляции и компоновки с этим случаем PETSc. Вы делаете то же самое с исходным исходным кодом, который не содержит PETSc и записывает компиляцию и связывает результаты процесса с ним.

Давайте предположим, что с PETSc-бесплатной версии, выход процесса компиляции г ++ -o ex1.o -I/random_path ex1.cpp и связь результата процесса является г ++ -w -o EX1 ex1.o -llib1 - L/random_lib2.

Следующий шаг - объединить пути компиляции для кода PETSc и кода без PETSc и того же со ссылкой. Таким образом, модифицированная компиляция и связывающие процессы будут:

Модифицированный Компиляция -

/usr/local/petsc/arch-linux2-c-debug/bin/mpicc -o ex1.o -c -fPIC -Wall -Wwrite-strings -Wno-strict-aliasing -Wno-unknown-pragmas -g3 -fno-inline -O0 -I/usr/local/petsc/include -I/usr/local/petsc/arch-linux2-c-debug/include –I/random_path ex1.cpp

Модифицированный Linking -

g++ -w -o ex1 ex1.o -Wl,-rpath,/usr/local/petsc/arch-linux2-c-debug/lib -L/usr/local/petsc/arch-linux2-c-debug/lib -lpetsc -Wl,-rpath,/usr/local/petsc/arch-linux2-c-debug/lib -lflapack -lfblas -lX11 -lpthread -lm -Wl,-rpath,/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -Wl,-rpath,/usr/lib/x86_64-linux-gnu -L/usr/lib/x86_64-linux-gnu -Wl,-rpath,/lib/x86_64-linux-gnu -L/lib/x86_64-linux-gnu -lmpichf90 -lgfortran -lm -lgfortran -lm -lquadmath -lm -lmpichcxx -lstdc++ -ldl -lmpich -lopa -lmpl -lrt -lpthread -lgcc_s –ldl –llib1 –L/random_lib2

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

Пример кода PETSc, который вычисляет обратные числа в массиве приведена ниже для справки:

// EX1.CPP 
#include <petscvec.h> 
#include <petscmat.h> 
#include <petscksp.h> 

Vec Arr2Vec(double *arr2, int SIZE); 

// MAIN FUNCTION 
int main(int argc,char **argv) 
{ 
    // Initialize PetSc 
    PetscInitialize(&argc,&argv,(char*)0,"Testing a program!"); 

    // Initialize parameters 
    int SIZE = 3; 
    PetscErrorCode ierr; 

    // **** Create a regular arary and set it with random numbers 
    double * arr2; 
    arr2 = new double [SIZE]; 

    arr2[0] = 0.1; 
    arr2[1] = 0.4; 
    arr2[2] = 0.2; 

    // Convert regular arary to PETSc vector [Note that this must do the same effect as the two-step process of conversion from regular array to PETSc arary and that to PETSc vector as listed above] 
    Vec x = Arr2Vec(arr2, SIZE); 

    printf("Reciprocal Vector : \n"); VecReciprocal(x); 
    VecView(x,PETSC_VIEWER_STDOUT_WORLD); 

    //Cleanup 
    ierr = VecDestroy(&x); 
    CHKERRQ(ierr); 
    PetscFinalize(); 

    return 0; 
} 

Vec Arr2Vec(double *arr2, int SIZE) 
{ 
    PetscScalar *array1; 
    PetscMalloc(SIZE*sizeof(PetscScalar),&array1); 

    for(int i=0;i<SIZE;i++) 
    array1[i]=arr2[i]; 

    // Setup vector 
    Vec x; 
    VecCreate(PETSC_COMM_WORLD,&x); 
    VecSetSizes(x,PETSC_DECIDE,SIZE); 
    VecSetFromOptions(x); 

    // Place PetSc array as Vector 
    VecPlaceArray(x,array1); 

    return x; 

} 
+0

Большое спасибо за подробное объяснение. Я собираюсь применить метод, который вы упомянули. Тем временем я использую NetBeans как инструмент для компиляции файлов PETSc вместе со своим собственным кодом на C++. Использование NetBeans позволяет мне избежать написания make-файла, потому что он создает сам make-файл. Если вам интересно узнать, как скомпилировать NetBeans, я был бы признателен, если вы расскажете, как это сделать. – Nazi

+0

Я как бы старая школа и стараюсь держаться подальше от IDE. Но я вернусь к вам, если попытаюсь использовать NetBeans. Цените свою помощь тоже! – Divakar

+0

Кроме того, у меня есть несколько других настраиваемых кодов для обмена данными между регулярными массивами C/C++, массивами PETSc и векторами PETSc. Дайте мне знать, если вам нужно больше примеров. – Divakar

2

редактировать: Хотя это старый пост, я уверен, что есть еще люди борются с этим.

Кроме того, вещи, по-видимому, слегка изменились для petsc 3.6.x (и slepc 3.6.x).

настоящее время я использую следующие строки в моем убунту 14.04 LTS Makefile для F90 файлов (с использованием как PETSc 3.6.1 и 3.6.0 slepc):

# PETSC and SLEPC directories 
PETSC_DIR = /opt/petsc-3.6.1 
SLEPC_DIR = /opt/slepc-3.6.0 
include $(PETSC_DIR)/lib/petsc/conf/variables 
include $(SLEPC_DIR)/lib/slepc/conf/slepc_variables 

С помощью этого можно построить

# Compiler command 
COMPILE = $(COMP_DIR) $(COMP_FLAGS) $(PETSC_FC_INCLUDES) $(SLEPC_INCLUDE) 

COMP_DIR, где должен быть установлен вручную (например, COMP_DIR = /usr/bin/mpif90 или COMP_DIR = /usr/bin/gfortran) и COMP_FLAGS дополнительные флаги (например, «-g O0»), а также

# Link command 
LINK = $(LINK_DIR) &(LINK_FLAGS) 

, где снова LINK_DIR необходимо установить вручную (напр. /usr/bin/g++) и LINK_FLAGS содержит дополнительные флаги (например, -fPIC).

Они могут быть использованы для создания правил для компиляции файлов F90 (я уверен, что C очень похож):

%.o : %.f90 
$(COMPILE) -c $< 

и основная программа:

main: $(ObjectFiles) main.o 
$(LINK) -o [email protected] $(ObjectFiles) main.o $(LINK_LIB) $(PETSC_LIB) $(SLEPC_LIB) 

где ObjectFiles содержит список всех файлов в проекте и LINK_LIB соответствует другим ссылкам (например, -lgfortran).

Это прекрасно работает для меня, но предложения по улучшению всегда приветствуются.

оригинальный пост: Вместо хака описываемого Divakar, вы можете легко узнать ссылку флаги и включают в себя каталоги для компиляции, запустив

make getlinklibs 
make getincludedirs 

в главном каталоге PETSc, как описано here ...

+0

Большое спасибо за ваше предложение. Кстати, я решил проблему, с которой я столкнулся, используя Netbeans вместо написания makefile. Я создал проект в Netbeans и добавил библиотеки, которые нужны из PETSc (которые мы можем найти с помощью getlinklib). – Nazi