├── .github └── workflows │ ├── cmake.yml │ ├── meson.yml │ ├── oneapi-linux.yml.bak │ ├── oneapi_cache_exclude_linux.sh │ └── oneapi_setup_apt_repo_linux.sh ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── cmake ├── Modules │ └── FindMPI.cmake ├── compilers.cmake ├── mpi.cmake ├── mpi_launcher.cmake ├── openmpi.cmake └── print_target_props.cmake ├── dev └── unit.cmake ├── meson.build └── test ├── CMakeLists.txt ├── basic.c ├── basic.f90 ├── helloworld.f90 ├── meson.build ├── mpivers.c ├── mpivers.f90 └── thread_pass.f90 /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: cmake 2 | 3 | on: 4 | push: 5 | paths: 6 | - "**.f90" 7 | - "**.F90" 8 | - "**.cmake" 9 | - "**/CMakeLists.txt" 10 | - ".github/workflows/cmake.yml" 11 | 12 | 13 | jobs: 14 | 15 | linux: 16 | runs-on: ubuntu-latest 17 | 18 | strategy: 19 | matrix: 20 | mpi: [openmpi, mpich] 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: install prereqs (linux) 26 | if: runner.os == 'Linux' 27 | run: sudo apt -yq install --no-install-recommends lib${{ matrix.mpi }}-dev ninja-build 28 | 29 | - name: install prereqs (mac) 30 | if: runner.os == 'macOS' 31 | run: brew install ${{ matrix.mpi }} ninja 32 | 33 | - run: cmake --workflow --preset debug 34 | 35 | - run: cmake --workflow --preset release 36 | -------------------------------------------------------------------------------- /.github/workflows/meson.yml: -------------------------------------------------------------------------------- 1 | name: meson 2 | 3 | on: 4 | push: 5 | paths: 6 | - "**.f90" 7 | - "**/meson.build" 8 | - ".github/workflows/meson.yml" 9 | 10 | 11 | jobs: 12 | 13 | linux-openmpi: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: actions/setup-python@v4 18 | with: 19 | python-version: '3.x' 20 | 21 | - name: install prereqs 22 | run: | 23 | pip install meson ninja 24 | sudo apt -yq update 25 | sudo apt -yq install --no-install-recommends libopenmpi-dev 26 | 27 | - run: meson setup build 28 | - run: meson compile -C build 29 | - run: meson test -C build -v 30 | -------------------------------------------------------------------------------- /.github/workflows/oneapi-linux.yml.bak: -------------------------------------------------------------------------------- 1 | name: oneapi-linux 2 | 3 | env: 4 | LINUX_CPP_COMPONENTS: intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic 5 | LINUX_FORTRAN_COMPONENTS: intel-oneapi-compiler-fortran 6 | LINUX_MKL_COMPONENTS: "intel-oneapi-mkl intel-oneapi-mkl-devel" 7 | LINUX_MPI_COMPONENTS: "intel-oneapi-mpi intel-oneapi-mpi-devel" 8 | # https://github.com/oneapi-src/oneapi-ci/blob/master/.github/workflows/build_all.yml 9 | CTEST_NO_TESTS_ACTION: error 10 | CC: icx 11 | FC: ifx 12 | 13 | on: 14 | push: 15 | paths: 16 | - "**.c" 17 | - "**.f" 18 | - "**.F" 19 | - "**.f90" 20 | - "**.F90" 21 | - "**.cmake" 22 | - "**/CMakeLists.txt" 23 | - ".github/workflows/oneapi-linux.yml" 24 | 25 | 26 | jobs: 27 | 28 | linux: 29 | runs-on: ubuntu-latest 30 | timeout-minutes: 10 31 | 32 | steps: 33 | - uses: actions/checkout@v4 34 | 35 | - name: cache install oneAPI 36 | id: cache-install 37 | uses: actions/cache@v3 38 | with: 39 | path: | 40 | /opt/intel/oneapi 41 | key: install-apt 42 | 43 | - name: non-cache install oneAPI 44 | if: steps.cache-install.outputs.cache-hit != 'true' 45 | timeout-minutes: 10 46 | run: | 47 | sh -c .github/workflows/oneapi_setup_apt_repo_linux.sh 48 | sudo apt install --no-install-recommends ${{ env.LINUX_CPP_COMPONENTS }} ${{ env.LINUX_FORTRAN_COMPONENTS }} ${{ env.LINUX_MPI_COMPONENTS }} 49 | 50 | - name: Setup Intel oneAPI environment 51 | run: | 52 | source /opt/intel/oneapi/setvars.sh 53 | printenv >> $GITHUB_ENV 54 | 55 | - name: patch PATH (this should be done by setvar.sh) 56 | run: echo "/opt/intel/oneapi/compiler/latest/bin" >> $GITHUB_PATH 57 | 58 | - name: print env 59 | run: printenv 60 | 61 | - name: ls compiler dir 62 | run: ls /opt/intel/oneapi/compiler/ 63 | 64 | - name: install Ninja 65 | run: sudo apt install ninja-build 66 | # install ninja needs to be own step as not cached by design 67 | 68 | - name: Release workflow 69 | run: cmake --workflow --preset debug 70 | 71 | - name: Release workflow 72 | run: cmake --workflow --preset release 73 | 74 | - name: exclude unused files from cache 75 | if: steps.cache-install.outputs.cache-hit != 'true' 76 | run: sh -c .github/workflows/oneapi_cache_exclude_linux.sh 77 | -------------------------------------------------------------------------------- /.github/workflows/oneapi_cache_exclude_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # SPDX-FileCopyrightText: 2020 Intel Corporation 4 | # 5 | # SPDX-License-Identifier: MIT 6 | 7 | #shellcheck disable=SC2010 8 | LATEST_VERSION=$(ls -1 /opt/intel/oneapi/compiler/ | grep -v latest | sort | tail -1) 9 | 10 | sudo rm -rf /opt/intel/oneapi/compiler/"$LATEST_VERSION"/linux/compiler/lib/ia32_lin 11 | sudo rm -rf /opt/intel/oneapi/compiler/"$LATEST_VERSION"/linux/bin/ia32 12 | sudo rm -rf /opt/intel/oneapi/compiler/"$LATEST_VERSION"/linux/lib/emu 13 | sudo rm -rf /opt/intel/oneapi/compiler/"$LATEST_VERSION"/linux/lib/oclfpga 14 | -------------------------------------------------------------------------------- /.github/workflows/oneapi_setup_apt_repo_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # SPDX-FileCopyrightText: 2020 Intel Corporation 4 | # 5 | # SPDX-License-Identifier: MIT 6 | 7 | wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB 8 | sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB 9 | echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list 10 | sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/oneAPI.list" -o APT::Get::List-Cleanup="0" 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19...3.29) 2 | 3 | project(FortranMPIexamples 4 | LANGUAGES C Fortran 5 | ) 6 | 7 | enable_testing() 8 | 9 | message(STATUS "CMake ${CMAKE_VERSION} Generator ${CMAKE_GENERATOR} Build type ${CMAKE_BUILD_TYPE}") 10 | 11 | # list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) 12 | 13 | # this has checks that can be reused in other projects as well 14 | include(cmake/mpi.cmake) 15 | include(cmake/mpi_launcher.cmake) 16 | 17 | include(cmake/print_target_props.cmake) 18 | print_target_props(MPI::MPI_Fortran) 19 | 20 | include(cmake/compilers.cmake) 21 | 22 | add_subdirectory(test) 23 | 24 | file(GENERATE OUTPUT .gitignore CONTENT "*") 25 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 6, 3 | 4 | "configurePresets": [ 5 | { 6 | "name": "default", 7 | "binaryDir": "${sourceDir}/build", 8 | "cacheVariables": { 9 | "CMAKE_COMPILE_WARNING_AS_ERROR": true 10 | } 11 | }, 12 | { 13 | "name": "multi", "inherits": "default", 14 | "displayName": "Ninja Multi-Config", 15 | "generator": "Ninja Multi-Config" 16 | } 17 | ], 18 | "buildPresets": [ 19 | { 20 | "name": "default", 21 | "configurePreset": "default" 22 | }, 23 | { 24 | "name": "release", 25 | "configurePreset": "multi", 26 | "configuration": "Release" 27 | }, 28 | { 29 | "name": "debug", 30 | "configurePreset": "multi", 31 | "configuration": "Debug" 32 | } 33 | ], 34 | "testPresets": [ 35 | { 36 | "name": "default", 37 | "configurePreset": "default", 38 | "output": { 39 | "outputOnFailure": true, 40 | "verbosity": "verbose" 41 | }, 42 | "execution": { 43 | "noTestsAction": "error", 44 | "scheduleRandom": true, 45 | "stopOnFailure": false, 46 | "timeout": 30 47 | } 48 | }, 49 | { 50 | "name": "release", "inherits": "default", 51 | "configurePreset": "multi", 52 | "configuration": "Release" 53 | }, 54 | { 55 | "name": "debug", "inherits": "default", 56 | "configurePreset": "multi", 57 | "configuration": "Debug" 58 | } 59 | ], 60 | "workflowPresets": [ 61 | { 62 | "name": "default", 63 | "steps": [ 64 | { 65 | "type": "configure", 66 | "name": "default" 67 | }, 68 | { 69 | "type": "build", 70 | "name": "default" 71 | }, 72 | { 73 | "type": "test", 74 | "name": "default" 75 | } 76 | ] 77 | }, 78 | { 79 | "name": "debug", 80 | "steps": [ 81 | { 82 | "type": "configure", 83 | "name": "multi" 84 | }, 85 | { 86 | "type": "build", 87 | "name": "debug" 88 | }, 89 | { 90 | "type": "test", 91 | "name": "debug" 92 | } 93 | ] 94 | }, 95 | { 96 | "name": "release", 97 | "steps": [ 98 | { 99 | "type": "configure", 100 | "name": "multi" 101 | }, 102 | { 103 | "type": "build", 104 | "name": "release" 105 | }, 106 | { 107 | "type": "test", 108 | "name": "release" 109 | } 110 | ] 111 | } 112 | ] 113 | } 114 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fortran MPI Examples 2 | 3 | [![cmake](https://github.com/scivision/fortran-mpi-examples/actions/workflows/cmake.yml/badge.svg)](https://github.com/scivision/fortran-mpi-examples/actions/workflows/cmake.yml) 4 | A few very basic examples, perhaps use to test MPI-3 Fortran library functionality. 5 | 6 | Free, popular MPI-3 interfaces for C and Fortran include: 7 | 8 | * [OpenMPI](https://www.open-mpi.org/) (Linux, Mac) 9 | * [MPICH](https://www.mpich.org/) (Linux, Mac) 10 | * [Intel MPI](https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/mpi-library.html) (Linux, Windows) 11 | 12 | Build and self-test: 13 | 14 | ```sh 15 | cmake --workflow --preset default 16 | ``` 17 | 18 | or step-by-step 19 | 20 | ```sh 21 | cmake -Bbuild 22 | 23 | cmake --build build 24 | 25 | ctest --test-dir build -V 26 | ``` 27 | 28 | This repo also gives an example of a workaround for OpenMPI 4.x and mpiexec race condition with large CPU count by setting TMPDIR to a short path name so as not to exceed 100 characters for UNIX sockets. 29 | 30 | ## Message Passing 31 | 32 | Pass data between two MPI threads. 33 | In this usage, MPI_Recv blocks waiting for MPI_Send 34 | 35 | ```sh 36 | mpiexec -np 2 mpi/mpi_pass 37 | ``` 38 | 39 | ## Notes 40 | 41 | See 42 | [OpenMPI docs](https://www.open-mpi.org/faq/?category=running#adding-ompi-to-path) 43 | re: setting PATH and LD_LIBRARY_PATH if CMake has trouble finding OpenMPI for a compiler. 44 | 45 | * https://hpc-forge.cineca.it/files/CoursesDev/public/2017/MasterCS/CalcoloParallelo/MPI_Master2017.pdf 46 | 47 | ### Cray 48 | 49 | FindMPI.cmake on Cray defines a rather sparse imported target MPI::MPI_C and MPI::MPI_Fortran like 50 | 51 | ``` 52 | -- Target: MPI::MPI_Fortran properties 53 | -- MPI::MPI_Fortran IMPORTED = TRUE 54 | -- MPI::MPI_Fortran NAME = MPI::MPI_Fortran 55 | -- MPI::MPI_Fortran SYSTEM = ON 56 | -- MPI::MPI_Fortran TYPE = INTERFACE_LIBRARY 57 | 58 | -- Target: MPI::MPI_C properties 59 | -- MPI::MPI_C IMPORTED = TRUE 60 | -- MPI::MPI_C NAME = MPI::MPI_C 61 | -- MPI::MPI_C SYSTEM = ON 62 | -- MPI::MPI_C TYPE = INTERFACE_LIBRARY 63 | ``` 64 | 65 | while on most non-Cray platforms the typical properties are also defined: INTERFACE_INCLUDE_DIRECTORIES, INTERFACE_LINK_LIBRARIES, INTERFACE_LINK_OPTIONS. 66 | Also on Cray. these typically defined variables are empty: MPI_Fortran_LIBRARIES, MPI_Fortran_MODULE_DIR, MPI_Fortran_INCLUDE_DIRS, MPI_Fortran_COMPILE_OPTIONS, MPI_Fortran_LINK_FLAGS. 67 | 68 | ### MPI-3 Fortran 69 | 70 | If "mpi_f08.mod" is not found, typically the MPI include directories are also missing. 71 | You can manually check if mpi_f08.mod is preset under the include "-I" directories from: 72 | 73 | ```sh 74 | mpif90 -show 75 | ``` 76 | -------------------------------------------------------------------------------- /cmake/Modules/FindMPI.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #[=======================================================================[.rst: 5 | FindMPI 6 | ------- 7 | 8 | SciVision www.scivision.dev 9 | 10 | Finds compiler flags or library necessary to use MPI library (MPICH, OpenMPI, MS-MPI, Intel MPI, ...) 11 | 12 | Components 13 | ========== 14 | 15 | MPI code languages are specified by components: 16 | 17 | ``C`` 18 | C interface for MPI--all MPI libraries have this. Default. 19 | 20 | ``CXX`` 21 | C++ interface for MPI (not all MPI libraries have C++ interface) 22 | 23 | ``Fortran`` 24 | Fortran interface for interface for MPI (some MPI libraries don't build this by default) 25 | 26 | 27 | Result Variables 28 | ^^^^^^^^^^^^^^^^ 29 | 30 | ``MPI_FOUND`` 31 | indicates MPI library found 32 | 33 | ``MPI__LIBRARIES`` 34 | libraries for 35 | 36 | ``MPI__INCLUDE_DIRS`` 37 | include dirs for 38 | 39 | ``MPI__LINK_FLAGS`` 40 | link flags for 41 | 42 | ``MPI__COMPILER`` 43 | compiler wrapper for 44 | 45 | ``MPI_Fortran_HAVE_F90_MODULE`` 46 | has MPI-2 Fortran 90 interface 47 | 48 | ``MPI_Fortran_HAVE_F08_MODULE`` 49 | has MPI-3 Fortran 2008 interface 50 | 51 | Imported Targets 52 | ^^^^^^^^^^^^^^^^ 53 | 54 | ``MPI::MPI_`` 55 | imported target for e.g. ``MPI::MPI_C`` or ``MPI::MPI_Fortran`` 56 | 57 | 58 | #]=======================================================================] 59 | include(CheckSourceCompiles) 60 | 61 | set(CMAKE_REQUIRED_FLAGS) 62 | 63 | 64 | function(get_flags exec outvar) 65 | 66 | execute_process(COMMAND ${exec} -show 67 | OUTPUT_STRIP_TRAILING_WHITESPACE 68 | OUTPUT_VARIABLE ret 69 | RESULT_VARIABLE code 70 | TIMEOUT 10 71 | ) 72 | 73 | if(code EQUAL 0) 74 | set(${outvar} ${ret} PARENT_SCOPE) 75 | endif() 76 | 77 | endfunction(get_flags) 78 | 79 | 80 | function(get_link_flags raw outvar) 81 | 82 | 83 | string(REGEX MATCHALL "(^| )(${CMAKE_LIBRARY_PATH_FLAG})([^\" ]+|\"[^\"]+\")" _Lflags "${raw}") 84 | list(TRANSFORM _Lflags STRIP) 85 | set(_flags ${_Lflags}) 86 | 87 | # check if compiler absolute path is first element and remove 88 | if("${raw}" MATCHES "^/") 89 | if("${_flags}" MATCHES "^/") 90 | list(REMOVE_AT _flags 0) 91 | endif() 92 | endif() 93 | 94 | # Linker flags "-Wl,..." 95 | string(REGEX MATCHALL "(^| )(-Wl,)([^\" ]+|\"[^\"]+\")" _Wflags "${raw}") 96 | list(TRANSFORM _Wflags STRIP) 97 | if(_Wflags) 98 | # this transform avoids CMake stripping out all "-Wl,rpath" after first. 99 | # Example: 100 | # -Wl,rpath -Wl,/path/to/A -Wl,rpath -Wl,/path/to/B 101 | # becomes 102 | # -Wl,-rpath,/path/to/A -Wl,-rpath,/path/to/B 103 | list(TRANSFORM _Wflags REPLACE "-Wl," "LINKER:") 104 | 105 | list(LENGTH _Wflags L) 106 | math(EXPR L "${L}-1") 107 | set(_work) 108 | set(skip -1) 109 | foreach(i RANGE ${L}) 110 | list(GET _Wflags ${i} f) 111 | if("${f}" MATCHES "(^| )(LINKER:)([^\" ]+|\"[^\"]+\")") 112 | # attach to prior rpath 113 | if("${CMAKE_MATCH_3}" STREQUAL "-rpath") 114 | # "LINKER:-rpath" with path as next argument 115 | math(EXPR j "${i}+1") 116 | list(GET _Wflags ${j} fp) 117 | string(SUBSTRING "${fp}" 7 -1 p) # path without LINKER: prefix 118 | 119 | if(IS_DIRECTORY "${p}") 120 | # it's an rpath,directory so skip this flag next iteration 121 | string(APPEND f ",${p}") 122 | set(skip ${j}) 123 | else() 124 | # if not a directory, just append it in the next iteration 125 | endif() 126 | elseif(i EQUAL ${skip}) 127 | # already added in prior step 128 | continue() 129 | endif() 130 | endif() 131 | 132 | list(APPEND _work "${f}") 133 | endforeach() 134 | 135 | list(APPEND _flags "${_work}") 136 | 137 | else(_Wflags) 138 | 139 | pop_flag("${raw}" -Xlinker _Xflags) 140 | if(_Xflags) 141 | set(CMAKE_C_LINKER_WRAPPER_FLAG "-Xlinker" " ") 142 | set(CMAKE_CXX_LINKER_WRAPPER_FLAG "-Xlinker" " ") 143 | set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Xlinker" " ") 144 | string(REPLACE ";" "," _Xflags "${_Xflags}") 145 | list(APPEND _flags "LINKER:${_Xflags}") 146 | endif() 147 | 148 | endif(_Wflags) 149 | 150 | set(${outvar} "${_flags}" PARENT_SCOPE) 151 | 152 | endfunction(get_link_flags) 153 | 154 | 155 | function(pop_flag raw flag outvar) 156 | # this gives the argument to flags to get their paths like -I or -l or -L 157 | 158 | set(_v) 159 | string(REGEX MATCHALL "(^| )${flag} *([^\" ]+|\"[^\"]+\")" _vars "${raw}") 160 | foreach(_p IN LISTS _vars) 161 | string(REGEX REPLACE "(^| )${flag} *" "" _p "${_p}") 162 | list(APPEND _v "${_p}") 163 | endforeach() 164 | 165 | set(${outvar} ${_v} PARENT_SCOPE) 166 | 167 | endfunction(pop_flag) 168 | 169 | 170 | function(pop_path raw outvar) 171 | # these are file paths without flags like /usr/lib/mpi.so 172 | 173 | if(MSVC) 174 | return() 175 | endif() 176 | 177 | set(flag /) 178 | set(_v) 179 | string(REGEX MATCHALL "(^| )${flag} *([^\" ]+|\"[^\"]+\")" _vars "${raw}") 180 | foreach(_p IN LISTS _vars) 181 | string(REGEX REPLACE "(^| )${flag} *" "" _p "${_p}") 182 | list(APPEND _v "/${_p}") 183 | endforeach() 184 | 185 | # check if compiler absolute path is first element and remove 186 | if("${raw}" MATCHES "^/") 187 | list(REMOVE_AT _v 0) 188 | endif() 189 | 190 | set(${outvar} ${_v} PARENT_SCOPE) 191 | 192 | endfunction(pop_path) 193 | 194 | 195 | function(find_c) 196 | 197 | # mpich / openmpi / Intel MPI: mpi 198 | # MS-MPI: msmpi 199 | # Intel Windows: impi 200 | 201 | set(MPI_C_LIBRARY) 202 | 203 | if(WIN32) 204 | if(CMAKE_C_COMPILER_ID MATCHES "^Intel") 205 | set(mpi_libname impi) 206 | else() 207 | set(mpi_libname msmpi) 208 | endif() 209 | else() 210 | set(mpi_libname mpi) 211 | endif() 212 | 213 | if(CMAKE_C_COMPILER_ID MATCHES "^Intel") 214 | set(wrap_name mpiicc mpiicc.bat) 215 | else() 216 | set(wrap_name mpicc mpicc.openmpi mpicc.mpich) 217 | endif() 218 | 219 | find_program(MPI_C_COMPILER 220 | NAMES ${wrap_name} 221 | HINTS ${pc_mpi_c_PREFIX} ${_hints} 222 | NAMES_PER_DIR 223 | PATHS ${_binpref} 224 | PATH_SUFFIXES ${mpi_binsuf} 225 | DOC "MPI C compiler wrapper" 226 | ) 227 | if(MPI_C_COMPILER) 228 | cmake_path(GET MPI_C_COMPILER PARENT_PATH mpi_root) 229 | cmake_path(GET mpi_root PARENT_PATH mpi_root) 230 | 231 | get_flags(${MPI_C_COMPILER} c_raw) 232 | if(c_raw) 233 | pop_flag(${c_raw} -I inc_dirs) 234 | pop_flag(${c_raw} ${CMAKE_LIBRARY_PATH_FLAG} mpi_libdirs) 235 | 236 | pop_path(${c_raw} MPI_C_LIBRARY_fullpath) 237 | 238 | get_link_flags(${c_raw} MPI_C_LINK_FLAGS) 239 | endif(c_raw) 240 | endif(MPI_C_COMPILER) 241 | 242 | find_library(MPI_C_LIBRARY 243 | NAMES ${mpi_libname} 244 | HINTS ${mpi_libdirs} ${mpi_root} ${pc_mpi_c_LIBRARY_DIRS} ${pc_mpi_c_LIBDIR} ${_hints} 245 | PATH_SUFFIXES ${mpi_libsuf} 246 | DOC "MPI C library" 247 | ) 248 | 249 | list(APPEND MPI_C_LIBRARY ${MPI_C_LIBRARY_fullpath}) 250 | 251 | find_path(MPI_C_INCLUDE_DIR 252 | NAMES mpi.h 253 | HINTS ${inc_dirs} ${mpi_root} ${pc_mpi_c_INCLUDE_DIRS} ${_hints} ${_hints_inc} 254 | DOC "MPI C include directory" 255 | ) 256 | if(NOT (MPI_C_LIBRARY AND MPI_C_INCLUDE_DIR)) 257 | return() 258 | endif() 259 | 260 | set(CMAKE_REQUIRED_INCLUDES ${MPI_C_INCLUDE_DIR}) 261 | set(CMAKE_REQUIRED_LINK_OPTIONS ${MPI_C_LINK_FLAGS}) 262 | set(CMAKE_REQUIRED_LIBRARIES ${MPI_C_LIBRARY}) 263 | list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) 264 | 265 | if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/find_mpi/get_mpi_version.c) 266 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/find_mpi/get_mpi_version.c 267 | [=[ 268 | #include 269 | #include 270 | 271 | int main(void) { 272 | int version, subversion; 273 | 274 | int ierr = MPI_Get_version(&version, &subversion); 275 | if (ierr != 0) return 1; 276 | printf("CMAKE_MPI_VERSION %d.%d\n", version, subversion); 277 | 278 | return 0; 279 | } 280 | ]=] 281 | ) 282 | endif() 283 | 284 | if(NOT MPI_VERSION) 285 | message(CHECK_START "Checking MPI API level") 286 | 287 | try_run(mpi_run_code mpi_build_code 288 | ${CMAKE_CURRENT_BINARY_DIR}/find_mpi/build 289 | ${CMAKE_CURRENT_BINARY_DIR}/find_mpi/get_mpi_version.c 290 | CMAKE_FLAGS -DINCLUDE_DIRECTORIES=${MPI_C_INCLUDE_DIR} 291 | LINK_OPTIONS ${MPI_C_LINK_FLAGS} 292 | LINK_LIBRARIES ${MPI_C_LIBRARY} 293 | RUN_OUTPUT_VARIABLE MPI_VERSION_STRING 294 | ) 295 | 296 | if(mpi_build_code AND mpi_run_code EQUAL 0) 297 | if("${MPI_VERSION_STRING}" MATCHES "CMAKE_MPI_VERSION ([0-9]+\\.[0-9]+)") 298 | set(MPI_VERSION ${CMAKE_MATCH_1} CACHE STRING "MPI API level") 299 | message(CHECK_PASS "${MPI_VERSION}") 300 | endif() 301 | endif() 302 | 303 | if(NOT MPI_VERSION) 304 | message(CHECK_FAIL "MPI API not detected with: 305 | MPI_C_LIBRARY: ${MPI_C_LIBRARY} 306 | MPI_C_INCLUDE_DIR: ${MPI_C_INCLUDE_DIR} 307 | MPI_C_LINK_FLAGS: ${MPI_C_LINK_FLAGS}" 308 | ) 309 | return() 310 | endif() 311 | endif() 312 | 313 | check_source_compiles(C 314 | [=[ 315 | #include 316 | #ifndef NULL 317 | #define NULL 0 318 | #endif 319 | int main(void) { 320 | MPI_Init(NULL, NULL); 321 | MPI_Finalize(); 322 | return 0; 323 | } 324 | ]=] 325 | MPI_C_links) 326 | 327 | if(MPI_C_links) 328 | set(MPI_C_INCLUDE_DIR ${MPI_C_INCLUDE_DIR} PARENT_SCOPE) 329 | set(MPI_C_LIBRARY "${MPI_C_LIBRARY}" PARENT_SCOPE) 330 | set(MPI_C_LINK_FLAGS "${MPI_C_LINK_FLAGS}" PARENT_SCOPE) 331 | set(MPI_C_FOUND true PARENT_SCOPE) 332 | endif() 333 | 334 | endfunction(find_c) 335 | 336 | 337 | function(find_cxx) 338 | 339 | # mpich / openmpi / IntelMPI: mpi 340 | # MS-MPI: msmpi 341 | # Intel Windows: impi 342 | 343 | set(MPI_CXX_LIBRARY) 344 | 345 | if(WIN32) 346 | if(CMAKE_CXX_COMPILER_ID MATCHES "^Intel") 347 | set(mpi_libname impi) 348 | else() 349 | set(mpi_libname msmpi) 350 | endif() 351 | elseif(DEFINED ENV{I_MPI_ROOT}) 352 | set(mpi_libname mpicxx) 353 | else() 354 | set(mpi_libname mpi_cxx mpi) 355 | endif() 356 | 357 | if(NOT (MPI_ROOT OR DEFINED MPI_CXX_COMPILER)) 358 | pkg_search_module(pc_mpi_cxx ompi-cxx ompi mpich) 359 | endif() 360 | 361 | if(CMAKE_CXX_COMPILER_ID MATCHES "^Intel") 362 | set(wrap_name mpiicpc mpiicpc.bat) 363 | else() 364 | set(wrap_name mpicxx mpicxx.openmpi mpicxx.mpich) 365 | endif() 366 | 367 | find_program(MPI_CXX_COMPILER 368 | NAMES ${wrap_name} 369 | HINTS ${pc_mpi_cxx_PREFIX} ${_hints} 370 | NAMES_PER_DIR 371 | PATHS ${_binpref} 372 | PATH_SUFFIXES ${mpi_binsuf} 373 | DOC "MPI C++ compiler wrapper" 374 | ) 375 | if(MPI_CXX_COMPILER) 376 | cmake_path(GET MPI_CXX_COMPILER PARENT_PATH mpi_root) 377 | cmake_path(GET mpi_root PARENT_PATH mpi_root) 378 | 379 | get_flags(${MPI_CXX_COMPILER} cxx_raw) 380 | if(cxx_raw) 381 | pop_flag(${cxx_raw} -I inc_dirs) 382 | pop_flag(${cxx_raw} ${CMAKE_LIBRARY_PATH_FLAG} mpi_libdirs) 383 | 384 | pop_path(${cxx_raw} MPI_CXX_LIBRARY) 385 | 386 | get_link_flags(${cxx_raw} MPI_CXX_LINK_FLAGS) 387 | endif(cxx_raw) 388 | endif(MPI_CXX_COMPILER) 389 | 390 | foreach(n ${mpi_libname}) 391 | find_library(MPI_CXX_${n}_LIBRARY 392 | NAMES ${n} 393 | HINTS ${mpi_libdirs} ${mpi_root} ${pc_mpi_cxx_LIBRARY_DIRS} ${pc_mpi_cxx_LIBDIR} ${_hints} 394 | PATH_SUFFIXES ${mpi_libsuf} 395 | DOC "MPI C++ library" 396 | ) 397 | if(MPI_CXX_${n}_LIBRARY) 398 | list(APPEND MPI_CXX_LIBRARY ${MPI_CXX_${n}_LIBRARY}) 399 | endif() 400 | endforeach() 401 | 402 | find_path(MPI_CXX_INCLUDE_DIR 403 | NAMES mpi.h 404 | HINTS ${inc_dirs} ${mpi_root} ${pc_mpi_cxx_INCLUDE_DIRS} ${_hints} ${_hints_inc} 405 | DOC "MPI C++ include directory" 406 | ) 407 | if(NOT (MPI_CXX_LIBRARY AND MPI_CXX_INCLUDE_DIR)) 408 | return() 409 | endif() 410 | 411 | set(CMAKE_REQUIRED_INCLUDES ${MPI_CXX_INCLUDE_DIR}) 412 | set(CMAKE_REQUIRED_LINK_OPTIONS ${MPI_CXX_LINK_FLAGS}) 413 | set(CMAKE_REQUIRED_LIBRARIES ${MPI_CXX_LIBRARY}) 414 | list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) 415 | 416 | check_source_compiles(CXX 417 | [=[ 418 | #include 419 | #ifndef NULL 420 | #define NULL 0 421 | #endif 422 | int main(void) { 423 | MPI_Init(NULL, NULL); 424 | MPI_Finalize(); 425 | return 0; 426 | } 427 | ]=] 428 | MPI_CXX_links) 429 | 430 | if(MPI_CXX_links) 431 | set(MPI_CXX_INCLUDE_DIR ${MPI_CXX_INCLUDE_DIR} PARENT_SCOPE) 432 | set(MPI_CXX_LIBRARY "${MPI_CXX_LIBRARY}" PARENT_SCOPE) 433 | set(MPI_CXX_LINK_FLAGS "${MPI_CXX_LINK_FLAGS}" PARENT_SCOPE) 434 | set(MPI_CXX_FOUND true PARENT_SCOPE) 435 | endif() 436 | 437 | endfunction(find_cxx) 438 | 439 | 440 | function(find_fortran) 441 | 442 | # mpich / openmpi / Intel MPI: mpi 443 | # MS-MPI: msmpi 444 | # Intel Windows: impi 445 | 446 | set(MPI_Fortran_LIBRARY) 447 | 448 | if(WIN32) 449 | if(CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") 450 | set(mpi_libname impi) 451 | else() 452 | set(mpi_libname msmpi) 453 | endif() 454 | elseif(DEFINED ENV{I_MPI_ROOT}) 455 | set(mpi_libname mpifort) 456 | else() 457 | set(mpi_libname 458 | mpi_usempif08 mpi_usempi_ignore_tkr mpi_mpifh 459 | mpifort 460 | mpi) 461 | endif() 462 | 463 | if(NOT (MPI_ROOT OR DEFINED MPI_Fortran_COMPILER)) 464 | pkg_search_module(pc_mpi_f ompi-fort ompi mpich) 465 | endif() 466 | 467 | if(CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") 468 | set(wrap_name mpiifort mpiifort.bat) 469 | else() 470 | set(wrap_name mpifort mpifc mpifort.openmpi mpifort.mpich) 471 | endif() 472 | 473 | find_program(MPI_Fortran_COMPILER 474 | NAMES ${wrap_name} 475 | HINTS ${pc_mpi_f_PREFIX} ${_hints} 476 | NAMES_PER_DIR 477 | PATHS ${_binpref} 478 | PATH_SUFFIXES ${mpi_binsuf} 479 | DOC "MPI Fortran compiler wrapper" 480 | ) 481 | if(MPI_Fortran_COMPILER) 482 | cmake_path(GET MPI_Fortran_COMPILER PARENT_PATH mpi_root) 483 | cmake_path(GET mpi_root PARENT_PATH mpi_root) 484 | 485 | get_flags(${MPI_Fortran_COMPILER} f_raw) 486 | if(f_raw) 487 | pop_flag(${f_raw} -I inc_dirs) 488 | pop_flag(${f_raw} ${CMAKE_LIBRARY_PATH_FLAG} mpi_libdirs) 489 | 490 | pop_path(${f_raw} MPI_Fortran_LIBRARY) 491 | 492 | get_link_flags(${f_raw} MPI_Fortran_LINK_FLAGS) 493 | endif(f_raw) 494 | endif(MPI_Fortran_COMPILER) 495 | 496 | foreach(n ${mpi_libname}) 497 | find_library(MPI_Fortran_${n}_LIBRARY 498 | NAMES ${n} 499 | HINTS ${mpi_libdirs} ${mpi_root} ${pc_mpi_f_LIBRARY_DIRS} ${pc_mpi_f_LIBDIR} ${_hints} 500 | PATH_SUFFIXES ${mpi_libsuf} 501 | DOC "MPI Fortran library" 502 | ) 503 | if(MPI_Fortran_${n}_LIBRARY) 504 | list(APPEND MPI_Fortran_LIBRARY ${MPI_Fortran_${n}_LIBRARY}) 505 | endif() 506 | endforeach() 507 | 508 | find_path(MPI_Fortran_INCLUDE_DIR 509 | NAMES mpi.mod 510 | HINTS ${inc_dirs} ${mpi_root} ${pc_mpi_f_INCLUDE_DIRS} ${_hints} ${_hints_inc} 511 | PATH_SUFFIXES lib 512 | # openmpi puts .mod files into lib/ 513 | DOC "MPI Fortran module directory" 514 | ) 515 | 516 | if(WIN32 AND NOT CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") 517 | find_path(MPI_Fortran_INCLUDE_EXTRA 518 | NAMES mpifptr.h 519 | HINTS ${inc_dirs} ${mpi_root} ${pc_mpi_f_INCLUDE_DIRS} ${_hints} ${_hints_inc} 520 | PATH_SUFFIXES x64 521 | DOC "MPI Fortran include directory" 522 | ) 523 | 524 | if(MPI_Fortran_INCLUDE_EXTRA AND NOT MPI_Fortran_INCLUDE_EXTRA STREQUAL ${MPI_Fortran_INCLUDE_DIR}) 525 | list(APPEND MPI_Fortran_INCLUDE_DIR ${MPI_Fortran_INCLUDE_EXTRA}) 526 | endif() 527 | endif() 528 | 529 | if(NOT (MPI_Fortran_LIBRARY AND MPI_Fortran_INCLUDE_DIR)) 530 | return() 531 | endif() 532 | 533 | set(CMAKE_REQUIRED_INCLUDES ${MPI_Fortran_INCLUDE_DIR}) 534 | set(CMAKE_REQUIRED_LINK_OPTIONS ${MPI_Fortran_LINK_FLAGS}) 535 | set(CMAKE_REQUIRED_LIBRARIES ${MPI_Fortran_LIBRARY}) 536 | list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) 537 | 538 | check_source_compiles(Fortran 539 | [=[ 540 | program test 541 | use mpi 542 | implicit none 543 | integer :: i 544 | call mpi_init(i) 545 | call mpi_finalize(i) 546 | end program 547 | ]=] 548 | MPI_Fortran_links) 549 | 550 | check_source_compiles(Fortran 551 | [=[ 552 | program test 553 | use mpi_f08, only : mpi_comm_rank, mpi_comm_world, mpi_init, mpi_finalize 554 | implicit none 555 | call mpi_init 556 | call mpi_finalize 557 | end program 558 | ]=] 559 | MPI_Fortran_HAVE_F08_MODULE) 560 | 561 | if(MPI_Fortran_links) 562 | set(MPI_Fortran_INCLUDE_DIR ${MPI_Fortran_INCLUDE_DIR} PARENT_SCOPE) 563 | set(MPI_Fortran_LIBRARY "${MPI_Fortran_LIBRARY}" PARENT_SCOPE) 564 | set(MPI_Fortran_LINK_FLAGS "${MPI_Fortran_LINK_FLAGS}" PARENT_SCOPE) 565 | set(MPI_Fortran_HAVE_F90_MODULE true PARENT_SCOPE) 566 | set(MPI_Fortran_HAVE_F08_MODULE ${MPI_Fortran_HAVE_F08_MODULE} PARENT_SCOPE) 567 | set(MPI_Fortran_FOUND true PARENT_SCOPE) 568 | endif() 569 | 570 | endfunction(find_fortran) 571 | 572 | #===== main program ====== 573 | 574 | set(_hints) 575 | set(_hints_inc) 576 | set(mpi_libsuf) 577 | 578 | find_package(PkgConfig) 579 | find_package(Threads) 580 | 581 | if(NOT MPI_ROOT AND DEFINED ENV{MPI_ROOT}) 582 | set(MPI_ROOT $ENV{MPI_ROOT}) 583 | endif() 584 | 585 | # Intel MPI, which works with non-Intel compilers on Linux 586 | if((CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_C_COMPILER_ID MATCHES "^Intel") AND 587 | DEFINED ENV{I_MPI_ROOT}) 588 | set(_hints $ENV{I_MPI_ROOT}) 589 | set(mpi_libsuf release) # Linux and Windows 590 | endif() 591 | 592 | if(WIN32 AND NOT CMAKE_C_COMPILER_ID MATCHES "^Intel") 593 | set(_hints $ENV{MSMPI_LIB64}) 594 | set(_hints_inc $ENV{MSMPI_INC}) 595 | endif() 596 | 597 | set(mpi_binsuf) 598 | if(NOT HDF5_ROOT AND NOT DEFINED ENV{I_MPI_ROOT}) 599 | set(mpi_binsuf bin openmpi/bin mpich/bin) 600 | endif() 601 | 602 | if(UNIX) 603 | set(_binpref /usr/lib64) 604 | else() 605 | set(_binpref $ENV{MINGWROOT} $ENV{MSMPI_BIN}) 606 | endif() 607 | 608 | if(NOT (MPI_ROOT OR DEFINED MPI_C_COMPILER)) 609 | pkg_search_module(pc_mpi_c ompi-c ompi mpich) 610 | endif() 611 | 612 | # must have MPIexec to be worthwhile (de facto standard is mpiexec) 613 | find_program(MPIEXEC_EXECUTABLE 614 | NAMES mpiexec 615 | HINTS ${pc_mpi_c_PREFIX} ${_hints} 616 | PATHS ${_binpref} 617 | PATH_SUFFIXES ${mpi_binsuf} 618 | DOC "MPI program runner" 619 | ) 620 | 621 | # like factory FindMPI, always find MPI_C 622 | find_c() 623 | 624 | if(CXX IN_LIST MPI_FIND_COMPONENTS) 625 | find_cxx() 626 | endif() 627 | 628 | if(Fortran IN_LIST MPI_FIND_COMPONENTS) 629 | find_fortran() 630 | endif() 631 | 632 | include(FindPackageHandleStandardArgs) 633 | find_package_handle_standard_args(MPI 634 | REQUIRED_VARS MPIEXEC_EXECUTABLE 635 | VERSION_VAR MPI_VERSION 636 | HANDLE_COMPONENTS) 637 | 638 | if(MPI_C_FOUND) 639 | set(MPI_C_LIBRARIES ${MPI_C_LIBRARY}) 640 | set(MPI_C_INCLUDE_DIRS ${MPI_C_INCLUDE_DIR}) 641 | if(NOT TARGET MPI::MPI_C) 642 | add_library(MPI::MPI_C IMPORTED INTERFACE) 643 | set_target_properties(MPI::MPI_C PROPERTIES 644 | INTERFACE_LINK_LIBRARIES "${MPI_C_LIBRARIES}" 645 | INTERFACE_INCLUDE_DIRECTORIES "${MPI_C_INCLUDE_DIRS}" 646 | ) 647 | if(MPI_C_LINK_FLAGS) 648 | set_property(TARGET MPI::MPI_C PROPERTY INTERFACE_LINK_OPTIONS "${MPI_C_LINK_FLAGS}") 649 | endif() 650 | endif() 651 | endif(MPI_C_FOUND) 652 | 653 | if(MPI_CXX_FOUND) 654 | set(MPI_CXX_LIBRARIES ${MPI_CXX_LIBRARY}) 655 | set(MPI_CXX_INCLUDE_DIRS ${MPI_CXX_INCLUDE_DIR}) 656 | if(NOT TARGET MPI::MPI_CXX) 657 | add_library(MPI::MPI_CXX IMPORTED INTERFACE) 658 | set_target_properties(MPI::MPI_CXX PROPERTIES 659 | INTERFACE_LINK_LIBRARIES "${MPI_CXX_LIBRARIES}" 660 | INTERFACE_INCLUDE_DIRECTORIES "${MPI_CXX_INCLUDE_DIRS}" 661 | ) 662 | if(MPI_CXX_LINK_FLAGS) 663 | set_property(TARGET MPI::MPI_CXX PROPERTY INTERFACE_LINK_OPTIONS "${MPI_CXX_LINK_FLAGS}") 664 | endif() 665 | endif() 666 | endif(MPI_CXX_FOUND) 667 | 668 | if(MPI_Fortran_FOUND) 669 | set(MPI_Fortran_LIBRARIES ${MPI_Fortran_LIBRARY}) 670 | set(MPI_Fortran_INCLUDE_DIRS ${MPI_Fortran_INCLUDE_DIR}) 671 | if(NOT TARGET MPI::MPI_Fortran) 672 | add_library(MPI::MPI_Fortran IMPORTED INTERFACE) 673 | set_target_properties(MPI::MPI_Fortran PROPERTIES 674 | INTERFACE_LINK_LIBRARIES "${MPI_Fortran_LIBRARIES}" 675 | INTERFACE_INCLUDE_DIRECTORIES "${MPI_Fortran_INCLUDE_DIRS}" 676 | ) 677 | if(MPI_Fortran_LINK_FLAGS) 678 | set_property(TARGET MPI::MPI_Fortran PROPERTY INTERFACE_LINK_OPTIONS "${MPI_Fortran_LINK_FLAGS}") 679 | endif() 680 | endif() 681 | 682 | endif(MPI_Fortran_FOUND) 683 | 684 | if(MPI_FOUND) 685 | set(MPIEXEC_NUMPROC_FLAG "-n" CACHE STRING "Flag used by MPI to specify the number of processes for mpiexec; the next option will be the number of processes.") 686 | cmake_host_system_information(RESULT _n QUERY NUMBER_OF_PHYSICAL_CORES) 687 | set(MPIEXEC_MAX_NUMPROCS "${_n}" CACHE STRING "Maximum number of processors available to run MPI applications.") 688 | 689 | message(VERBOSE "FindMPI results: 690 | MPI_C_COMPILER: ${MPI_C_COMPILER} 691 | MPI_C_LIBRARIES: ${MPI_C_LIBRARIES} 692 | MPI_C_INCLUDE_DIRS: ${MPI_C_INCLUDE_DIRS} 693 | MPI_C_LINK_FLAGS: ${MPI_C_LINK_FLAGS} 694 | 695 | MPI_Fortran_COMPILER: ${MPI_Fortran_COMPILER} 696 | MPI_Fortran_LIBRARIES: ${MPI_Fortran_LIBRARIES} 697 | MPI_Fortran_INCLUDE_DIRS: ${MPI_Fortran_INCLUDE_DIRS} 698 | MPI_Fortran_LINK_FLAGS: ${MPI_Fortran_LINK_FLAGS} 699 | 700 | MPIEXEC_EXECUTABLE: ${MPIEXEC_EXECUTABLE} 701 | MPIEXEC_MAX_NUMPROCS: ${MPIEXEC_MAX_NUMPROCS} 702 | MPI_VERSION: ${MPI_VERSION} 703 | ") 704 | endif() 705 | 706 | mark_as_advanced( 707 | MPI_Fortran_LIBRARY MPI_Fortran_INCLUDE_DIR MPI_Fortran_HAVE_F90_MODULE MPI_Fortran_HAVE_F08_MODULE 708 | MPI_C_LIBRARY MPI_C_INCLUDE_DIR 709 | MPIEXEC_EXECUTABLE MPIEXEC_NUMPROC_FLAG MPIEXEC_MAX_NUMPROCS 710 | ) 711 | -------------------------------------------------------------------------------- /cmake/compilers.cmake: -------------------------------------------------------------------------------- 1 | if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|Intel") 2 | add_compile_options($<$:-Wall>) 3 | endif() 4 | 5 | if(CMAKE_C_COMPILER_ID STREQUAL "GNU") 6 | add_compile_options( 7 | "$<$,$>:-Wextra>" 8 | ) 9 | endif() 10 | 11 | if(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") 12 | add_compile_options($<$:-Wall>) 13 | add_compile_options( 14 | "$<$,$>:-Wextra;-fcheck=all;-Werror=array-bounds>" 15 | ) 16 | 17 | elseif(CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") 18 | add_compile_options( 19 | "$<$:-warn>" 20 | "$<$,$>:-check;-traceback>" 21 | "$<$:-Rno-debug-disables-optimization>" 22 | ) 23 | endif() 24 | -------------------------------------------------------------------------------- /cmake/mpi.cmake: -------------------------------------------------------------------------------- 1 | include(CheckSourceCompiles) 2 | 3 | set(MPI_DETERMINE_LIBRARY_VERSION true) 4 | 5 | find_package(MPI REQUIRED COMPONENTS C Fortran) 6 | 7 | message(STATUS "MPI Library Version: ${MPI_C_LIBRARY_VERSION_STRING}") 8 | 9 | message(STATUS "${MPI_Fortran_LIBRARY_VERSION_STRING}") 10 | 11 | message(STATUS "MPI_Fortran_LIBRARIES: ${MPI_Fortran_LIBRARIES}") 12 | 13 | message(STATUS "MPI_Fortran_MODULE_DIR: ${MPI_Fortran_MODULE_DIR}") 14 | message(STATUS "MPI_Fortran_INCLUDE_DIRS: ${MPI_Fortran_INCLUDE_DIRS}") 15 | message(STATUS "MPI_Fortran_COMPILE_OPTIONS: ${MPI_Fortran_COMPILE_OPTIONS}") 16 | message(STATUS "MPI_Fortran_LINK_FLAGS: ${MPI_Fortran_LINK_FLAGS}") 17 | 18 | include(${CMAKE_CURRENT_LIST_DIR}/openmpi.cmake) 19 | 20 | if(MPI_Fortran_HAVE_F08_MODULE) 21 | return() 22 | endif() 23 | 24 | set(CMAKE_REQUIRED_LIBRARIES MPI::MPI_Fortran) 25 | 26 | # sometimes factory FindMPI.cmake doesn't define this 27 | message(CHECK_START "Checking for Fortran MPI-3 binding") 28 | check_source_compiles(Fortran 29 | [=[ 30 | program test 31 | use mpi_f08, only : mpi_comm_rank, mpi_real, mpi_comm_world, mpi_init, mpi_finalize 32 | implicit none 33 | call mpi_init 34 | call mpi_finalize 35 | end program 36 | ]=] 37 | MPI_Fortran_HAVE_F08_MODULE 38 | ) 39 | 40 | if(MPI_Fortran_HAVE_F08_MODULE) 41 | message(CHECK_PASS "yes") 42 | else() 43 | message(CHECK_FAIL "no") 44 | message(WARNING "MPI-3 Fortran module mpi_f08 not found, builds may fail.") 45 | endif() 46 | -------------------------------------------------------------------------------- /cmake/mpi_launcher.cmake: -------------------------------------------------------------------------------- 1 | function(test_mpi_launcher target test Nworker) 2 | 3 | if(NOT (DEFINED MPIEXEC_EXECUTABLE AND DEFINED MPIEXEC_NUMPROC_FLAG)) 4 | message(FATAL_ERROR "MPIEXEC_EXECUTABLE and MPIEXEC_NUMPROC_FLAG must be defined to use test_mpi_launcher") 5 | endif() 6 | 7 | if(NOT Nworker) 8 | message(FATAL_ERROR "Nworker must be defined to use test_mpi_launcher") 9 | endif() 10 | 11 | if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.29) 12 | set_property(TARGET ${target} PROPERTY TEST_LAUNCHER ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${Nworker}) 13 | else() 14 | set_property(TARGET ${target} PROPERTY CROSSCOMPILING_EMULATOR ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${Nworker}) 15 | endif() 16 | 17 | set_property(TEST ${test} PROPERTY PROCESSORS ${Nworker}) 18 | 19 | if(DEFINED mpi_tmpdir) 20 | set_property(TEST ${test} PROPERTY ENVIRONMENT "TMPDIR=${mpi_tmpdir}") 21 | endif() 22 | 23 | endfunction() 24 | -------------------------------------------------------------------------------- /cmake/openmpi.cmake: -------------------------------------------------------------------------------- 1 | # https://github.com/open-mpi/ompi/issues/7393 2 | # https://github.com/gerlero/openfoam-app/pull/112 3 | # https://apple.stackexchange.com/a/287710 4 | 5 | message(VERBOSE "MPI_C_LIBRARY_VERSION_STRING: ${MPI_C_LIBRARY_VERSION_STRING}") 6 | 7 | if(UNIX AND MPI_C_LIBRARY_VERSION_STRING MATCHES "Open[ ]?MPI") 8 | if(NOT DEFINED mpi_tmpdir) 9 | execute_process(COMMAND mktemp -d /tmp/mpi-XXXXXXXX 10 | RESULT_VARIABLE ret 11 | OUTPUT_VARIABLE mpi_tmpdir 12 | OUTPUT_STRIP_TRAILING_WHITESPACE 13 | TIMEOUT 10 14 | ) 15 | if(NOT ret EQUAL 0) 16 | message(FATAL_ERROR "could not create MPI working dir via mktemp -d: ${ret}") 17 | endif() 18 | set(mpi_tmpdir ${mpi_tmpdir} CACHE PATH "MPI working dir") 19 | message(STATUS "${ret}: Created MPI working dir ${mpi_tmpdir}") 20 | endif() 21 | endif() 22 | -------------------------------------------------------------------------------- /cmake/print_target_props.cmake: -------------------------------------------------------------------------------- 1 | execute_process(COMMAND ${CMAKE_COMMAND} --help-property-list 2 | OUTPUT_VARIABLE _props OUTPUT_STRIP_TRAILING_WHITESPACE 3 | ) 4 | 5 | STRING(REGEX REPLACE "\n" ";" _props "${_props}") 6 | 7 | list(REMOVE_DUPLICATES _props) 8 | 9 | function(print_target_props tgt) 10 | if(NOT TARGET ${tgt}) 11 | message(WARNING "Target ${tgt} not found") 12 | return() 13 | endif() 14 | 15 | message(STATUS "Target: ${tgt} properties") 16 | foreach(p IN LISTS _props) 17 | if(p MATCHES "" AND NOT CMAKE_BUILD_TYPE) 18 | continue() 19 | endif() 20 | 21 | string(REPLACE "" "${CMAKE_BUILD_TYPE}" p "${p}") 22 | 23 | get_property(v TARGET ${tgt} PROPERTY "${p}") 24 | if(v) 25 | message(STATUS "${tgt} ${p} = ${v}") 26 | endif() 27 | endforeach() 28 | endfunction() 29 | -------------------------------------------------------------------------------- /dev/unit.cmake: -------------------------------------------------------------------------------- 1 | # Unit tests for FindMPI.cmake 2 | 3 | function(get_flags exec outvar) 4 | 5 | execute_process(COMMAND ${exec} -show 6 | OUTPUT_STRIP_TRAILING_WHITESPACE 7 | OUTPUT_VARIABLE ret 8 | RESULT_VARIABLE code 9 | TIMEOUT 10 10 | ) 11 | if(NOT code EQUAL 0) 12 | return() 13 | endif() 14 | 15 | set(${outvar} ${ret} PARENT_SCOPE) 16 | 17 | endfunction(get_flags) 18 | 19 | 20 | function(get_link_flags raw outvar) 21 | 22 | 23 | string(REGEX MATCHALL "(^| )(${CMAKE_LIBRARY_PATH_FLAG})([^\" ]+|\"[^\"]+\")" _Lflags "${raw}") 24 | list(TRANSFORM _Lflags STRIP) 25 | set(_flags ${_Lflags}) 26 | 27 | # check if compiler absolute path is first element and remove 28 | if("${raw}" MATCHES "^/") 29 | if("${_flags}" MATCHES "^/") 30 | list(REMOVE_AT _flags 0) 31 | endif() 32 | endif() 33 | 34 | # Linker flags "-Wl,..." 35 | string(REGEX MATCHALL "(^| )(-Wl,)([^\" ]+|\"[^\"]+\")" _Wflags "${raw}") 36 | list(TRANSFORM _Wflags STRIP) 37 | if(_Wflags) 38 | # this transform avoids CMake stripping out all "-Wl,rpath" after first. 39 | # Example: 40 | # -Wl,rpath -Wl,/path/to/lib -Wl,rpath -Wl,/path/to/another 41 | list(TRANSFORM _Wflags REPLACE "-Wl," "LINKER:") 42 | list(APPEND _flags "${_Wflags}") 43 | else() 44 | pop_flag("${raw}" -Xlinker _Xflags) 45 | if(_Xflags) 46 | set(CMAKE_C_LINKER_WRAPPER_FLAG "-Xlinker" " ") 47 | set(CMAKE_CXX_LINKER_WRAPPER_FLAG "-Xlinker" " ") 48 | set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Xlinker" " ") 49 | string(REPLACE ";" "," _Xflags "${_Xflags}") 50 | list(APPEND _flags "LINKER:${_Xflags}") 51 | endif() 52 | endif() 53 | 54 | set(${outvar} "${_flags}" PARENT_SCOPE) 55 | 56 | endfunction(get_link_flags) 57 | 58 | 59 | function(pop_flag raw flag outvar) 60 | # this gives the argument to flags to get their paths like -I or -l or -L 61 | 62 | set(_v) 63 | string(REGEX MATCHALL "(^| )${flag} *([^\" ]+|\"[^\"]+\")" _vars "${raw}") 64 | foreach(_p IN LISTS _vars) 65 | string(REGEX REPLACE "(^| )${flag} *" "" _p "${_p}") 66 | list(APPEND _v "${_p}") 67 | endforeach() 68 | 69 | set(${outvar} ${_v} PARENT_SCOPE) 70 | 71 | endfunction(pop_flag) 72 | 73 | 74 | function(pop_path raw outvar) 75 | # these are file paths without flags like /usr/lib/mpi.so 76 | 77 | if(MSVC) 78 | return() 79 | endif() 80 | 81 | set(flag /) 82 | set(_v) 83 | string(REGEX MATCHALL "(^| )${flag} *([^\" ]+|\"[^\"]+\")" _vars "${raw}") 84 | foreach(_p IN LISTS _vars) 85 | string(REGEX REPLACE "(^| )${flag} *" "" _p "${_p}") 86 | list(APPEND _v "/${_p}") 87 | endforeach() 88 | 89 | # check if compiler absolute path is first element and remove 90 | if("${raw}" MATCHES "^/") 91 | list(REMOVE_AT _v 0) 92 | endif() 93 | 94 | set(${outvar} ${_v} PARENT_SCOPE) 95 | 96 | endfunction(pop_path) 97 | 98 | 99 | # ---- tests ---- 100 | 101 | set(CMAKE_LIBRARY_PATH_FLAG -L) 102 | 103 | # Cray mpifort -show 104 | function(cray_fortran) 105 | set(f_raw "gfortran -I/cm/shared/apps/openmpi/gcc/64/3.1.2_gcc8/include -pthread -I/cm/shared/apps/openmpi/gcc/64/3.1.2_gcc8/lib -L/usr/lib64 -L/opt/mellanox/mxm/lib -Wl,-rpath -Wl,/usr/lib64 -Wl,-rpath -Wl,/opt/mellanox/mxm/lib -Wl,-rpath -Wl,/cm/shared/apps/openmpi/gcc/64/3.1.2_gcc8/lib -Wl,--enable-new-dtags -L/cm/shared/apps/openmpi/gcc/64/3.1.2_gcc8/lib -lmpi_usempif08 -lmpi_usempi_ignore_tkr -lmpi_mpifh -lmpi") 106 | 107 | pop_flag(${f_raw} -I inc_dirs) 108 | pop_flag(${f_raw} ${CMAKE_LIBRARY_PATH_FLAG} lib_dirs) 109 | 110 | pop_flag(${f_raw} -l lib_names) 111 | 112 | pop_path(${f_raw} lib_paths) 113 | 114 | get_link_flags(${f_raw} MPI_Fortran_LINK_FLAGS) 115 | 116 | # Cray unit test 117 | if(lib_paths) 118 | message(FATAL_ERROR "lib_paths not present in Cray mpifort -show") 119 | endif() 120 | 121 | set(MPI_Fortran_LINK_FLAGS "${MPI_Fortran_LINK_FLAGS}" PARENT_SCOPE) 122 | endfunction(cray_fortran) 123 | 124 | cray_fortran() 125 | 126 | message(STATUS " 127 | MPI_Fortran_INCLUDE_DIR: ${inc_dirs} 128 | MPI_Fortran_LIBRARY_DIR: ${lib_dirs} 129 | MPI_Fortran_LIBRARY_NAMES: ${lib_names} 130 | MPI_Fortran_LIBRARY: ${lib_paths} 131 | MPI_Fortran_LINK_FLAGS: ${MPI_Fortran_LINK_FLAGS} 132 | ") 133 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('FortranMPIexamples', 'fortran', 'c', 2 | meson_version: '>= 0.57.0' 3 | ) 4 | 5 | 6 | fc = meson.get_compiler('fortran') 7 | 8 | mpi = dependency('mpi', language : 'fortran', required : false, disabler: true) 9 | code = ''' 10 | use mpi 11 | integer :: i 12 | call mpi_init(i) 13 | call mpi_finalize(i) 14 | end program''' 15 | if not fc.links(code, dependencies : mpi, name: 'Fortran MPI links') 16 | mpi = disabler() 17 | endif 18 | 19 | mpiexec = find_program('mpiexec', required : false, disabler: true) # MS-MPI has only mpiexec 20 | 21 | subdir('test') 22 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(mpi_basic_C basic.c) 2 | target_link_libraries(mpi_basic_C PRIVATE MPI::MPI_C) 3 | add_test(NAME MPIbasicC COMMAND mpi_basic_C) 4 | test_mpi_launcher(mpi_basic_C MPIbasicC 1) 5 | 6 | add_executable(mpi_version_C mpivers.c) 7 | target_link_libraries(mpi_version_C PRIVATE MPI::MPI_C) 8 | add_test(NAME MPIversionC COMMAND mpi_version_C) 9 | test_mpi_launcher(mpi_version_C MPIversionC 1) 10 | 11 | # --- Fortran MPI-3 12 | 13 | add_executable(mpi_basic_Fortran basic.f90) 14 | target_link_libraries(mpi_basic_Fortran PRIVATE MPI::MPI_Fortran) 15 | add_test(NAME MPIbasicFortran COMMAND mpi_basic_Fortran) 16 | test_mpi_launcher(mpi_basic_Fortran MPIbasicFortran 1) 17 | 18 | add_executable(mpi_version_Fortran mpivers.f90) 19 | target_link_libraries(mpi_version_Fortran PRIVATE MPI::MPI_Fortran) 20 | add_test(NAME MPIversionFortran COMMAND mpi_version_Fortran) 21 | test_mpi_launcher(mpi_version_Fortran MPIversionFortran 1) 22 | 23 | # --- more than one MPI image 24 | 25 | add_executable(mpi_hello helloworld.f90) 26 | target_link_libraries(mpi_hello PRIVATE MPI::MPI_Fortran) 27 | add_test(NAME MPIhello COMMAND mpi_hello) 28 | test_mpi_launcher(mpi_hello MPIhello ${MPIEXEC_MAX_NUMPROCS}) 29 | set_property(TEST MPIhello PROPERTY FIXTURES_SETUP mpi_fxt) 30 | 31 | # --- actual message passing 32 | 33 | add_executable(mpi_pass thread_pass.f90) 34 | target_link_libraries(mpi_pass PRIVATE MPI::MPI_Fortran) 35 | 36 | if(MPIEXEC_MAX_NUMPROCS GREATER_EQUAL 2) 37 | 38 | add_test(NAME MPIpass COMMAND mpi_pass) 39 | test_mpi_launcher(mpi_pass MPIpass 2) 40 | set_property(TEST MPIpass PROPERTY FIXTURES_REQUIRED mpi_fxt) 41 | 42 | endif() 43 | 44 | # --- test properties 45 | 46 | get_property(tests DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY TESTS) 47 | 48 | set_tests_properties(${tests} PROPERTIES 49 | RESOURCE_LOCK mpi 50 | SKIP_REGULAR_EXPRESSION "No host list provided" 51 | ) 52 | -------------------------------------------------------------------------------- /test/basic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | int main(int argc, char **argv) 7 | { 8 | printf("going to init MPI\n"); 9 | 10 | if(MPI_Init(&argc,&argv)) { 11 | perror("could not init MPI\n"); 12 | return EXIT_FAILURE; 13 | } 14 | printf("MPI Init OK\n"); 15 | 16 | if(MPI_Finalize()) { 17 | perror("could not close MPI\n"); 18 | return EXIT_FAILURE; 19 | } 20 | 21 | printf("MPI closed\n"); 22 | 23 | return EXIT_SUCCESS; 24 | } 25 | -------------------------------------------------------------------------------- /test/basic.f90: -------------------------------------------------------------------------------- 1 | program basic 2 | 3 | use mpi_f08 4 | 5 | implicit none (type, external) 6 | 7 | print *, "going to init MPI" 8 | 9 | call MPI_INIT() 10 | 11 | print *, "MPI Init OK" 12 | 13 | call MPI_FINALIZE() 14 | 15 | print *, "MPI closed" 16 | 17 | end program 18 | -------------------------------------------------------------------------------- /test/helloworld.f90: -------------------------------------------------------------------------------- 1 | program hw_mpi 2 | !! Each process prints out a "Hello, world!" message with a process ID 3 | !! Original Author: John Burkardt 4 | !! Modified: Michael Hirsch, Ph.D. 5 | 6 | use, intrinsic:: iso_fortran_env, only: dp=>real64, compiler_version 7 | 8 | use mpi_f08 9 | 10 | implicit none 11 | 12 | integer :: id, Nproc 13 | real(dp) :: wtime 14 | 15 | !> Initialize MPI. 16 | call MPI_Init() 17 | 18 | !> Get the number of processes. 19 | call MPI_Comm_size(MPI_COMM_WORLD, Nproc) 20 | 21 | !> Get the individual process ID. 22 | call MPI_Comm_rank(MPI_COMM_WORLD, id) 23 | 24 | !> Print a message. 25 | if (id == 0) then 26 | print *,compiler_version() 27 | wtime = MPI_Wtime() 28 | print *, 'number of processes: ', Nproc 29 | end if 30 | 31 | print *, 'Process ', id 32 | 33 | if (id == 0) then 34 | wtime = MPI_Wtime() - wtime 35 | print *, 'Elapsed wall clock time = ', wtime, ' seconds.' 36 | end if 37 | 38 | !> Shut down MPI. 39 | call MPI_Finalize() 40 | 41 | end program 42 | -------------------------------------------------------------------------------- /test/meson.build: -------------------------------------------------------------------------------- 1 | basic = executable('basic_f', 'basic.f90', dependencies : mpi) 2 | test('MPI Basic', basic, timeout : 5) 3 | 4 | 5 | ver = executable('mpivers', 'mpivers.f90', dependencies : mpi) 6 | test('MPI version check', ver, timeout: 10) 7 | 8 | hello = executable('mpi_hello', 'helloworld.f90', 9 | dependencies : mpi) 10 | test('MPI Hello World', mpiexec, 11 | is_parallel : false, 12 | args: ['-np', '2', hello], 13 | timeout: 20) 14 | 15 | 16 | pass = executable('mpi_pass', 'thread_pass.f90', dependencies : mpi) 17 | test('MPI thread pass', mpiexec, 18 | is_parallel : false, 19 | args: ['-np', '2', pass], 20 | timeout: 20) 21 | -------------------------------------------------------------------------------- /test/mpivers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char **argv) 5 | { 6 | int id, Nimg, ierr, L; 7 | char version[MPI_MAX_LIBRARY_VERSION_STRING]; 8 | 9 | ierr = MPI_Init(&argc,&argv); 10 | if(ierr != 0) { 11 | perror("could not init MPI"); 12 | return 1; 13 | } 14 | 15 | ierr = MPI_Comm_rank(MPI_COMM_WORLD, &id); 16 | if(ierr != 0) { 17 | perror("could not get MPI rank"); 18 | return 1; 19 | } 20 | MPI_Comm_size(MPI_COMM_WORLD, &Nimg); 21 | MPI_Get_library_version(version, &L); 22 | 23 | printf("MPI: Image %d / %d : %s",id, Nimg, version); 24 | 25 | ierr = MPI_Finalize(); 26 | if(ierr != 0) { 27 | perror("could not close MPI"); 28 | return 1; 29 | } 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /test/mpivers.f90: -------------------------------------------------------------------------------- 1 | program mpi_vers 2 | ! https://github.com/open-mpi/ompi/blob/master/examples/hello_usempif08.f90 3 | 4 | use, intrinsic :: iso_fortran_env, only : compiler_version 5 | 6 | use mpi_f08 7 | 8 | implicit none 9 | 10 | integer :: id, Nimg, vlen 11 | character(MPI_MAX_LIBRARY_VERSION_STRING) :: version ! allocatable not ok 12 | 13 | 14 | print *,compiler_version() 15 | 16 | call MPI_INIT() 17 | 18 | call MPI_COMM_RANK(MPI_COMM_WORLD, id) 19 | 20 | call MPI_COMM_SIZE(MPI_COMM_WORLD, Nimg) 21 | call MPI_GET_LIBRARY_VERSION(version, vlen) 22 | 23 | print '(A,I3,A,I3,A)', 'MPI: Image ', id, ' / ', Nimg, ':', trim(version) 24 | 25 | call MPI_FINALIZE() 26 | 27 | end program 28 | -------------------------------------------------------------------------------- /test/thread_pass.f90: -------------------------------------------------------------------------------- 1 | program mpi_pass 2 | !! passes data between two threads 3 | !! This would be much simpler using Fortran 2008 coarray syntax 4 | !! 5 | !! Original author: John Burkardt 6 | 7 | use, intrinsic :: iso_fortran_env, only: real32, compiler_version, int64 8 | 9 | use mpi_f08 10 | 11 | implicit none 12 | 13 | integer :: mcount 14 | real(real32) :: dat(0:99), val(200) 15 | integer :: dest, i, num_procs, id, tag 16 | integer(int64) :: tic, toc, rate 17 | 18 | type(MPI_STATUS) :: status 19 | 20 | call system_clock(tic) 21 | 22 | call MPI_Init() 23 | 24 | ! Determine this process's ID. 25 | call MPI_Comm_rank(MPI_COMM_WORLD, id) 26 | 27 | ! Find out the number of processes available. 28 | call MPI_Comm_size(MPI_COMM_WORLD, num_procs) 29 | 30 | if (num_procs < 2) error stop 'two threads are required, use: mpiexec -np 2 ./mpi_pass' 31 | 32 | if (id == 0) then 33 | print *,compiler_version() 34 | print *, 'Number of MPI processes available ', num_procs 35 | end if 36 | 37 | ! Process 0 expects to receive as much as 200 real values, from any source. 38 | select case (id) 39 | case (0) 40 | print *, id, "waiting for MPI_send() from image 1" 41 | call MPI_Recv (val, size(val), MPI_REAL, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, status) 42 | 43 | print *, id, ' Got data from processor ', status%MPI_SOURCE, 'tag',status%MPI_TAG 44 | 45 | call MPI_Get_count(status, MPI_REAL, mcount) 46 | 47 | print *, id, ' Got ', mcount, ' elements.' 48 | 49 | if (abs(val(5)-4) > epsilon(0.)) error stop "data did not transfer" 50 | 51 | ! Process 1 sends 100 real values to process 0. 52 | case (1) 53 | print *, id, ': setting up data to send to process 0.' 54 | 55 | dat = real([(i, i = 0, 99)]) 56 | 57 | dest = 0 58 | tag = 55 59 | call MPI_Send(dat, size(dat), MPI_REAL, dest, tag, MPI_COMM_WORLD) 60 | case default 61 | print *, id, ': MPI has no work for image', id 62 | end select 63 | 64 | call MPI_Finalize() 65 | 66 | 67 | if (id == 0) then 68 | call system_clock(toc) 69 | call system_clock(count_rate=rate) 70 | print *, 'Run time in seconds: ', real(toc - tic) / real(rate) 71 | end if 72 | 73 | end program 74 | --------------------------------------------------------------------------------