diff --git a/HySoP/CMakeLists.txt b/HySoP/CMakeLists.txt index d97db98eb0956f056e7125bb45c1a9b56c035994..9230491ccab9e8d516c6ada17271449396fc7249 100644 --- a/HySoP/CMakeLists.txt +++ b/HySoP/CMakeLists.txt @@ -5,23 +5,27 @@ # #======================================================= -# ============= Global Settings ============= -# Set minimum version -cmake_minimum_required(VERSION 2.6) +# ============= Global cmake Settings ============= +# Set minimum version for cmake +cmake_minimum_required(VERSION 2.8) # Set policy -cmake_policy(VERSION 2.6) +cmake_policy(VERSION 2.8) # Set cmake modules directory (i.e. the one which contains all user-defined FindXXX.cmake files among other things) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake) # Force out-of-source build include(OutOfSourceBuild) # Some usefull macros -include(Tools) +include(ParmesTools) # User defined options option(VERBOSE_MODE "enable verbose mode for cmake exec. Default = on" ON) option(WITH_PPM "link parmes with ppm when this mode is enable. Default = on." ON) option(WITH_MPI "compile and link parmes with mpi when this mode is enable. Default = on." ON) option(DOUBLEPREC "set precision for real numbers to double precision when this mode is enable. Default = on." ON) +option(WITH_TESTS "Enable testing. Default = on" ON) + +# default library type +set(BUILD_SHARED_LIBS 1) # ============= The project ============= # Set project name and project languages @@ -31,6 +35,13 @@ option(DOUBLEPREC "set precision for real numbers to double precision when this # Note that because of OutOfSourceBuild, binary_dir and source_dir must be different. set(PROJECT_NAME Parmes) project(${PROJECT_NAME} CXX C Fortran) +# Set a version number for the project +set(${PROJECT_NAME}_version 1.0.0) + +# ============= Tests ============= +if(WITH_TESTS) + enable_testing() +endif(WITH_TESTS) # ============= Prepare compilation ============= @@ -44,7 +55,7 @@ endif (NOT CMAKE_BUILD_TYPE) # If the project uses Fortran ... # Set module files directory (i.e. where .mod will be created) set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/Modules) -# To add compilation flags: +# Add compilation flags: append_Fortran_FLAGS("-Wall") # -------------------------------------------- @@ -94,20 +105,23 @@ endif(EXISTS ${CMAKE_SOURCE_DIR}/config.hpp.cmake) # -------------------------------------------- # Create executable or lib # -------------------------------------------- -# The list of all dirs containing sources to be compiled +# The list of all dirs containing sources to be compiled for the Parmes lib set(${PROJECT_NAME}_SRCDIRS src src/interfaces/Fortran2Cpp src/interfaces/ppm ) -# List of the possible file names extensions -set(EXTS -*.cxx -*.hpp -*.h -*.f90 + +# A main file to create an executable (test purpose) +set(${PROJECT_NAME}_MAINSRCDIRS +src/main ) +# List of the possible file names extensions +set(EXTS *.cxx *.hpp *.h *.f90) +# Note FP : we can also use cmake vars ${CMAKE_Fortran_SOURCE_FILE_EXTENSIONS} ${CMAKE_C_SOURCE_FILE_EXTENSIONS} ${CMAKE_CXX_SOURCE_FILE_EXTENSIONS} + +# Source files list: foreach(_DIR ${${PROJECT_NAME}_SRCDIRS}) set(_DIR_FILES) foreach(_EXT ${EXTS}) @@ -118,9 +132,15 @@ foreach(_DIR ${${PROJECT_NAME}_SRCDIRS}) endforeach(_EXT ${_ALL_EXTS}) endforeach(_DIR ${${PROJECT_NAME}_SRCDIRS}) -# Source files list: -#file(GLOB ${PROJECT_NAME}_SRC src/*.cxx src/*.f90 src/*.h src/*.hpp) -display(${PROJECT_NAME}_SRC) +foreach(_DIR ${${PROJECT_NAME}_MAINSRCDIRS}) + set(_DIR_FILES) + foreach(_EXT ${EXTS}) + file(GLOB _DIR_FILES_EXT ${_DIR}/${_EXT}) + if(_DIR_FILES_EXT) + list(APPEND ${PROJECT_NAME}_MAINSRC ${_DIR_FILES_EXT}) + endif(_DIR_FILES_EXT) + endforeach(_EXT ${_ALL_EXTS}) +endforeach(_DIR ${${PROJECT_NAME}_MAINSRCDIRS}) # -I include_directories(${${PROJECT_NAME}_SRCDIRS}) @@ -133,11 +153,29 @@ FortranCInterface_HEADER(${CMAKE_Fortran_MODULE_DIRECTORY}/FCMangle.h SYMBOL_NAMESPACE "PPM_" SYMBOLS init testPPM:init) +# Create the Parmes Library +add_library(${PROJECT_NAME}_shared ${${PROJECT_NAME}_SRC}) # Creates the executable -add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_SRC}) +add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_MAINSRC}) +add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_shared) +target_link_libraries(${PROJECT_NAME} ${PROJECT_NAME}_shared) target_link_libraries(${PROJECT_NAME} ${LIBS}) -set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) +# CXX is used as linker language +set_target_properties(${PROJECT_NAME} ${PROJECT_NAME}_shared PROPERTIES LINKER_LANGUAGE CXX) + +#add_executable(testF2003 ${${PROJECT_NAME}_TESTS_SRC}) +#target_link_libraries(testF2003 ${LIBS}) +#set_target_properties(testF2003 PROPERTIES LINKER_LANGUAGE CXX) + +if(WITH_TESTS) + message(STATUS "Enable testing ...") + begin_test(src/tests/F2003) + new_test(testAllocatedPtr userMod.f90 wrapper.f90 testAllocatedPtr.cxx) + new_test(testNullPtr userMod.f90 wrapper.f90 testNullPtr.cxx) + end_test() +endif(WITH_TESTS) + # -------------------------------------------- # RPATH # -------------------------------------------- @@ -152,16 +190,16 @@ set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib") # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - # ============= Prepare install ============= # The library -install(TARGETS ${PROJECT_NAME} # targets list +install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_shared # targets list RUNTIME DESTINATION bin # executables ARCHIVE DESTINATION lib # static libs LIBRARY DESTINATION lib # shared libs ) + # The headers and/or the modules install(FILES ${${PROJECT_NAME}_HDRS} DESTINATION include) install(DIRECTORY ${CMAKE_BINARY_DIR}/Modules DESTINATION include) diff --git a/HySoP/src/ParmesDef.hpp b/HySoP/src/ParmesDef.hpp index 0daa98fbf93cf41e6dca98ee0fe1fcc418dab231..e517ca7f7e59c1a50e6163d335e3c9baf4c59790 100644 --- a/HySoP/src/ParmesDef.hpp +++ b/HySoP/src/ParmesDef.hpp @@ -2,6 +2,7 @@ */ #ifndef PARMES_DEF_HPP #define PARMES_DEF_HPP +#include <boost/array.hpp> /** Global namespace for Parmes tools and functions*/ namespace Parmes { diff --git a/HySoP/src/interfaces/Fortran2Cpp/WrapC.hpp b/HySoP/src/interfaces/Fortran2Cpp/WrapC.hpp index 48ff1e5b51edb49160734319e6ea5205f6d97bf6..919a18e57f3472bb172a7c885afb5e4aeb17c317 100644 --- a/HySoP/src/interfaces/Fortran2Cpp/WrapC.hpp +++ b/HySoP/src/interfaces/Fortran2Cpp/WrapC.hpp @@ -6,12 +6,5 @@ typedef struct { double* elements; } C2FPtr; -extern "C" { - - void wrapC2F_allocatedPtr(double*, int*); - void wrapC2F_NULLPtr(C2FPtr*); - void wrapC2F_NULLPtrBis(double**, int*); - -} #endif diff --git a/HySoP/src/interfaces/Fortran2Cpp/WrapFortran.f90 b/HySoP/src/interfaces/Fortran2Cpp/WrapFortran.f90 index d73ecb2a67c2b8cd141433ded095bf122ac3ad9f..9a5c2028c1eec6b346b5e9ad5fc46db2e3ae0606 100644 --- a/HySoP/src/interfaces/Fortran2Cpp/WrapFortran.f90 +++ b/HySoP/src/interfaces/Fortran2Cpp/WrapFortran.f90 @@ -1,14 +1,13 @@ module WrapFort use iso_c_binding - use modTest implicit none - public wrapC2F_allocatedPtr, wrapC2F_NULLPtr, wrapC2F_NULLPtrBis + public aliasF2C !> A structure to bind C and fortran pointers - type, bind(C) :: C2FPtr + type, bind(C), public :: C2FPtr integer (c_int) :: length type (c_ptr) :: elements end type C2FPtr @@ -17,79 +16,6 @@ module WrapFort contains - !> Send an already allocated C pointer to a Fortran subroutine. - !! @param type(c_Ptr) a C pointer (void*) - !! @param type(c_int) size of C pointer - subroutine wrapC2F_allocatedPtr(cptr, sizeCptr) bind(C, name='wrapC2F_allocatedPtr') - - type(c_Ptr),intent(in),VALUE :: cptr - integer (kind=c_int), intent(IN) :: sizeCptr - - real(kind=c_double), pointer, dimension(:) :: xp => NULL() - - if(NDEBUG) print *, '=== wrapC2F_allocatedPtr ===' - ! Associate cptr and xp. - call c_f_pointer (cptr, xp, (/sizeCPtr/)) - - if(.not.associated(xp) ) then - print *, 'Error, association failed' - end if - - ! Do some stuff on xp ... - ! xp(1) = -3.9 - call cas3(xp) - print *, '=== End wrapC2F_allocatedPtr === ' - end subroutine WrapC2F_allocatedPtr - - - !> Send a NULL C pointer to a Fortran subroutine and get it back properly allocated - !! @param[inout] type(c_Ptr) a C pointer (void*) - !! @param[out] type(c_int) size of C pointer - subroutine wrapC2F_NULLPtr(vector) bind(C, name='wrapC2F_NULLPtr') - - type(C2FPtr) :: vector - - real(kind=c_double), pointer, dimension(:) :: xp => NULL() - - if(NDEBUG) print *, '=== wrapC2F_NULLPtr ===' - - call cas5(xp) - - if(.not.associated(xp) ) then - print *, 'Error, association failed' - end if - - vector%length = size(xp) - vector%elements = c_loc(xp(1)) - - print *, '=== End of wrapC2F_NULLPtr === ' - end subroutine wrapC2F_NULLPtr - - !> Send a NULL C pointer to a Fortran subroutine and get it back properly allocated - !! @param[inout] type(c_Ptr) a C pointer (void*) - !! @param[out] type(c_int) size of C pointer - subroutine wrapC2F_NULLPtrBis(vector, length) bind(C, name='wrapC2F_NULLPtrBis') - - type(c_ptr),intent(inout) :: vector - integer(c_int), intent(out) :: length - - real(kind=c_double), pointer, dimension(:) :: xp => NULL() - - if(NDEBUG) print *, '=== wrapC2F_NULLPtr ===' - - call cas5(xp) - -!!$ if(.not.associated(xp) ) then -!!$ print *, 'Error, association failed' -!!$ end if -!!$ length = size(xp) -!!$ vector= c_loc(xp(1)) - - call aliasF2C(vector, xp, length) - - print *, '=== End of wrapC2F_NULLPtr === ' - end subroutine wrapC2F_NULLPtrBis - subroutine aliasF2C(vectorC, vectorF, length) type(c_ptr),intent(inout) :: vectorC integer(c_int), intent(out) :: length diff --git a/HySoP/src/main.cxx b/HySoP/src/main/main.cxx similarity index 72% rename from HySoP/src/main.cxx rename to HySoP/src/main/main.cxx index 4316a565e08c6a6715773773d540faadbd9ba08c..05ac2056de8bc71ab7a51b8d61d66942ab69f17c 100644 --- a/HySoP/src/main.cxx +++ b/HySoP/src/main/main.cxx @@ -6,7 +6,6 @@ #include <string> #include <cstring> #include <Grid.hpp> -#include <boost/array.hpp> #include<ParmesDef.hpp> #include<Domain.hpp> #include<mpi.h> @@ -114,48 +113,4 @@ int main(int argc, char* argv[]) // std::cout << "yiha" << vect2[1] << std::endl; //Mesh* p_obj = 0 ; - - double * toto = 0; - - int nx=2, ny=2, nz=1; - double toto2[nx]; - - toto2[0] = 12.8; - toto2[nx-1]= 90.8; - //PPM::wrapper::bridgeC2F(&nx,toto2); - - //PPM::PPM_MODULE(modtest, bridge, MODTEST,BRIDGE)(&nx,&ny,&nz,toto); - //PPM::PPM_MODULE(modtest, application3, MODTEST,APPLICATION3)(); - - //PPM::PPM_MODULE(modtest, bridge2, MODTEST,BRIDGE2)(&nx,toto2); - - double * toto3 = 0; - //PPM::PPM_MODULE(modtest, testglob, MODTEST,TESTGLOB)(toto,&toto3); - int ntoto; - // PPM::PPM_MODULE(wrapfort, bridgef2c, WRAPFORTMODTEST,BRIDGEF2C)(&ntoto,toto); - - - //getFortranPtr(&toto); - - - //std::cout << "toto toto " << toto[0] << " " << toto[1]<< std::endl; - // std::cout << "totototo " << toto2[0] << " " << toto2[1]<< std::endl; - - std::cout << "TEST PPM ..." << std::endl; - - C2FPtr * myVector = new C2FPtr; - wrapC2F_NULLPtr(myVector); - - for(int i =0; i<myVector->length; ++i) - cout << myVector->elements[i] << endl; - - wrapC2F_NULLPtrBis(&toto, &ntoto); - - cout << ntoto << endl; - for(int i = 0; i<ntoto ;++i) - cout << toto[i] << endl; - - delete(myVector); - } - diff --git a/HySoP/src/tests/F2003/testAllocatedPtr.cxx b/HySoP/src/tests/F2003/testAllocatedPtr.cxx new file mode 100644 index 0000000000000000000000000000000000000000..40f329a18cdc506df865c760b4c9c74edbf67659 --- /dev/null +++ b/HySoP/src/tests/F2003/testAllocatedPtr.cxx @@ -0,0 +1,57 @@ +/** \file testAllocatedPtr.cxx + Test F2003 C interoperability + Send a vector (i.e allocated pointer) to Fortran. Must get it back still properly allocated with a different content. + + */ +#include<iostream> +#include <string> +#include "WrapC.hpp" +#include "ParmesDef.hpp" +#include<vector> +#include <math.h> + +using namespace std ; + +using Parmes::Def::real_t; + +// Declare the Fortran subroutine +extern "C" void wrapC2F_allocatedPtr(double*, int*, real_t*); + + +int main(int argc, char* argv[]) +{ + + int length = 12; + std::vector<real_t> myVector(length); + for(int i = 0; i<length; ++i) + myVector[i] = 2.3; + + real_t expectedContent = 1.1; + + // Send myVector to the Fortran Wrapper. + // myVector is supposed to be modified such that myVector[i] = expectedContent *i + wrapC2F_allocatedPtr(&myVector[0], &length, &expectedContent); + + for(int i = 0; i<length ; ++i) + cout << myVector[i] << endl; + + if(myVector.size()!= length) + { + cout << "ERROR" << endl; + return 1; + } + + + for(int i = 0; i< length ; ++i) + { + real_t check = myVector[i] - expectedContent*(i+1); + real_t tol = 1e-10; + if(fabs(check)>tol) + { + cout << "ERROR" << endl; + return 1; + } + } + +} + diff --git a/HySoP/src/tests/F2003/testNullPtr.cxx b/HySoP/src/tests/F2003/testNullPtr.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d552d8912080203aed9b04868ae3ae72c12b2ced --- /dev/null +++ b/HySoP/src/tests/F2003/testNullPtr.cxx @@ -0,0 +1,43 @@ +/** \file testNullPtr.cxx + Test F2003 C interoperability + + Send a null pointer to Fortran : must send back a properly allocated vector + + */ +#include<iostream> +#include <string> +#include "WrapC.hpp" + +using namespace std ; + +extern "C" { + + void wrapC2F_NULLPtr(C2FPtr*); + void wrapC2F_NULLPtrBis(double**, int*); + +} + +int main(int argc, char* argv[]) +{ + double * toto = 0; + int ntoto; + std::cout << "Fortran 2003 wrapper ..." << std::endl; + + // + C2FPtr * myVector = new C2FPtr; + + wrapC2F_NULLPtr(myVector); + + for(int i =0; i<myVector->length; ++i) + cout << myVector->elements[i] << endl; + + wrapC2F_NULLPtrBis(&toto, &ntoto); + + cout << ntoto << endl; + for(int i = 0; i<ntoto ;++i) + cout << toto[i] << endl; + + delete(myVector); + +} + diff --git a/HySoP/src/modTest.f90 b/HySoP/src/tests/F2003/userMod.f90 similarity index 55% rename from HySoP/src/modTest.f90 rename to HySoP/src/tests/F2003/userMod.f90 index c92143b05aa32a6a59829b0f0b0e3bd996a8e6a2..25870aa503fcd1ac4b1c80ab12f9f1f918818ff9 100644 --- a/HySoP/src/modTest.f90 +++ b/HySoP/src/tests/F2003/userMod.f90 @@ -1,41 +1,21 @@ -module modTest +module userMod implicit none - + contains - ! IN : an already allocated pointer with explicit size. - subroutine cas1(x) - - real*8, dimension(2) :: x - - x(2) = x(2) +1.65 - print *, 'cas 1', x(1), ' ', x(2) - - end subroutine cas1 - - ! IN an already allocated pointer with implicit size. - subroutine cas2(x) - - real*8, dimension(*), intent(inout) :: x - - - print *, 'cas2a', x(1), ' ', x(2) - - x(2) = x(2) +1.65 - print *, 'cas 2b', x(1), ' ', x(2) - - end subroutine cas2 - ! Already allocated pointer, no size information, intent(IN) - subroutine cas3(x) - - real(kind=8), dimension(:), intent(in) :: x - - !print *, 'cas3 ', shape(x) - print *, 'cas3a ', x(1), ' ', x(2) - - end subroutine cas3 + subroutine modifyX(x,factor) + + real(kind=8), dimension(:), intent(inout) :: x + real(kind=8), intent(in) :: factor + + integer :: i + do i=1,size(x) + x(i) = i*factor + end do + + end subroutine modifyX subroutine cas4(x) @@ -80,10 +60,7 @@ contains end subroutine cas6 subroutine Application3() - use temp - real, dimension(:), pointer :: x - call bibi(x) - print *, x + end subroutine Application3 -end module modTest +end module userMod diff --git a/HySoP/src/tests/F2003/wrapper.f90 b/HySoP/src/tests/F2003/wrapper.f90 new file mode 100644 index 0000000000000000000000000000000000000000..ef2db12eea93872301067b7e19ffa103cd149cc9 --- /dev/null +++ b/HySoP/src/tests/F2003/wrapper.f90 @@ -0,0 +1,86 @@ +module testWrap + + ! The fortran wrapper from Parmes + use WrapFort + ! Some subroutines for tests + use userMod + + implicit none + +contains + + !> Send an already allocated C pointer to a Fortran subroutine. + !! @param type(c_Ptr) a C pointer (void*) + !! @param type(c_int) size of C pointer + subroutine wrapC2F_allocatedPtr(cptr, sizeCptr, expectedContent) bind(C, name='wrapC2F_allocatedPtr') + + type(c_Ptr),intent(in),VALUE :: cptr + integer (kind=c_int), intent(IN) :: sizeCptr + real(kind = c_double), intent(IN) :: expectedContent + + real(kind=c_double), pointer, dimension(:) :: xp => NULL() + + if(NDEBUG) print *, '=== wrapC2F_allocatedPtr ===' + ! Associate cptr and xp. + call c_f_pointer (cptr, xp, (/sizeCPtr/)) + + if(.not.associated(xp) ) then + print *, 'Error, association failed' + end if + + ! Do some stuff on xp ... + xp(1) = -3.9 + call modifyX(xp,expectedContent) + print *, '=== End wrapC2F_allocatedPtr === ' + + end subroutine WrapC2F_allocatedPtr + + !> Send a NULL C pointer to a Fortran subroutine and get it back properly allocated + !! @param[inout] type(c_Ptr) a C pointer (void*) + !! @param[out] type(c_int) size of C pointer + subroutine wrapC2F_NULLPtr(vector) bind(C, name='wrapC2F_NULLPtr') + + type(C2FPtr) :: vector + + real(kind=c_double), pointer, dimension(:) :: xp => NULL() + + if(NDEBUG) print *, '=== wrapC2F_NULLPtr ===' + + call cas5(xp) + + if(.not.associated(xp) ) then + print *, 'Error, association failed' + end if + + vector%length = size(xp) + vector%elements = c_loc(xp(1)) + + print *, '=== End of wrapC2F_NULLPtr === ' + end subroutine wrapC2F_NULLPtr + + !> Send a NULL C pointer to a Fortran subroutine and get it back properly allocated + !! @param[inout] type(c_Ptr) a C pointer (void*) + !! @param[out] type(c_int) size of C pointer + subroutine wrapC2F_NULLPtrBis(vector, length) bind(C, name='wrapC2F_NULLPtrBis') + + type(c_ptr),intent(inout) :: vector + integer(c_int), intent(out) :: length + + real(kind=c_double), pointer, dimension(:) :: xp => NULL() + + if(NDEBUG) print *, '=== wrapC2F_NULLPtr ===' + + call cas5(xp) + +!!$ if(.not.associated(xp) ) then +!!$ print *, 'Error, association failed' +!!$ end if +!!$ length = size(xp) +!!$ vector= c_loc(xp(1)) + + call aliasF2C(vector, xp, length) + + print *, '=== End of wrapC2F_NULLPtr === ' + end subroutine wrapC2F_NULLPtrBis + +end module testWrap